前言
做为一款App,自定义主题色能为用户带来更加良好的体验。 此项目的需求是通过设置页改变App整体的主题颜色,并且使用到主题颜色的widget也同步更新其颜色。
文中所用环境及配置
flutter 2.2.3
provider 5.0.0
开始
theme_color 主题改变监听
class ThemeColor extends ChangeNotifier {
int _selectIndex;
ThemeColor(this._selectIndex);
///改变当前主题色
void selectColor(int index) {
_selectIndex = index;
SPUtil.setInt(AppConfig.themeColor, index);
///更新自定义颜色集中的主题色
Provider.of<MyColor>(Application.getContext(), listen: false).setColor(colors[index]);
notifyListeners();
}
int get selectIndex => _selectIndex;
}
///自定义的主题色
List<Color> colors = [
Colors.blue,
Colors.amber,
];
myColor 自定义颜色集
class MyColor extends ChangeNotifier {
Color color, _textColor;
MyColor({this.color}) {
if (color == null) color = colors[SPUtil.getInt(AppConfig.themeColor)];
_textColor = color.computeLuminance() < 0.5 ? Colors.white : Colors.black;
}
void setColor(Color color) {
this.color = color;
notifyListeners();
}
///随主题动态变化
Color get themeColor => color;
///主题色上的文本颜色,随主题色的亮度是否小于0.5而改变
Color get defaultTextColor => _textColor;
///以下为自定义的颜色集
static Color red = Colors.red;
}
main
void main() => realRunApp();
void realRunApp() async {
WidgetsFlutterBinding.ensureInitialized();
SizeUtil.initialize();
await SPUtil.getInstance();
//app首次打开,进行配置
if (!SPUtil.containsKey(AppConfig.firstOpen)) {
SPUtil.setBool(AppConfig.firstOpen, false); //置为非首次打开
SPUtil.setInt(AppConfig.themeColor, 0); //设置app默认主题颜色
}
runZonedGuarded(() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => ThemeColor(SPUtil.getInt(AppConfig.themeColor))),//设置主题色
ChangeNotifierProvider(create: (context) => MyColor(color: colors[SPUtil.getInt(AppConfig.themeColor)])),//设置颜色跟随主题色
],
child: MyApp(),
),
);
}, (error, stackTrace) {
print('error:$error-------------stack:\n$stackTrace');
}, zoneSpecification: ZoneSpecification(
print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
// 记录所有的打印日志
parent.print(zone, "$line");
},
));
}
MyApp
primarySwatch: colors[Provider.of<ThemeColor>(context).selectIndex]为当前主题色的引用,当ThemeColor中的selectIndex改变时,即可改变全局的主题色。
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'demo',
debugShowCheckedModeBanner: true,
theme: ThemeData(
primarySwatch: colors[Provider.of<ThemeColor>(context).selectIndex],
visualDensity: VisualDensity.adaptivePlatformDensity,
checkboxTheme: Theme.of(context).checkboxTheme.copyWith(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
),
textTheme: TextTheme(
),
),
initialRoute: RoutePaths.welcome,
onGenerateRoute: MyRoute.generateRoute,
navigatorObservers: [FlutterSmartDialog.observer],
navigatorKey: AppConfig.globalKey,
builder: (context, child) => MediaQuery(
//设置文字大小不随系统设置改变
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
child: Scaffold(
body: GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus &&
currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus.unfocus();
}
},
child: FlutterSmartDialog(child: child),
),
),
),
);
}
}
使用
index为当前所选颜色在自定义主题集colors的索引
Provider.of<ThemeColor>(context, listen: false).selectColor(index);
示例
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BaseWidget<HomeViewModel>(
model: HomeViewModel(),
onModelReady: (model) {},
appBar: AppBar(
title: Text("标题"),
),
child: (context, model) => Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ListView.builder(
shrinkWrap: true,
itemCount: colors.length,
itemBuilder: (_context, index) {
return MaterialButton(
color: colors[index],
onPressed: () {
Provider.of<ThemeColor>(context, listen: false).selectColor(index);
},
child: Text(
"改变",
),
);
},
),
SizedBox(height: 200,),
Container(
width: 200,
height: 100,
alignment: Alignment.center,
color: MyColor().themeColor,
child: Text(
"当前widget使用的主题色",
style: TextStyle(
color: MyColor().defaultTextColor,
),
),
),
],
),
);
}
}