记录flutter项目之——使用Provider管理改变全局主题色

568 阅读2分钟

前言

做为一款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,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

效果

70a6f001317299975b39a959a7197ed.jpg

8039230c3089ed73972e02c76367763.jpg