找回密码
 立即注册
首页 业界区 安全 Flutter自定义主题Theme最佳实践

Flutter自定义主题Theme最佳实践

纪音悦 3 小时前
Flutter中使用主题,基本都是通过ThemeData来进行的(不会有人用CupertinoThemeData吧,如果有,我敬你是个汉子)。而ThemeData的编写和定义,都牢牢的和Material Design风格绑定在了一起。
那么,问题来了,我们在开发过程中,设计师给出的设计稿,通常带有设计师自己的一套风格主题。
这些风格主题和被强绑定的Material Design风格,基本都是天差地别,没有一丝丝的相似。
这就出现了一些解决方案,不过基本都是自定义一个AppColors之类的类,然后通过状态管理框架(例如:Getx、Bloc、Provider等等)进行全局刷新。
这里就出现了一些纠结的地方:

  • Flutter中默认的Theme已经提供了切换的方法,无需再通过状态管理框架再写一次了,但是强制使用了Material Design风格,基本上和设计师给的冲突了。
  • 通过状态管理框架自己实现一套颜色配置,完全抛弃Theme提供的所有帮助。
其实,我们可以通过ThemeExtension来进行扩展,把我们的theme进行扩展。
来,上教程!
1. 先来一个AppColors压压惊

当然,无论怎样,都需要定义我们的AppColors。在这里,用来存放所有的设计师给的规范颜色值。
例如:
  1. import 'package:flutter/material.dart';
  2. /// app_colors.dart
  3. class AppLightColors {
  4.   static const Color demo1 = Colors.red; // 红色的
  5.   static const Color demo2 = Colors.green; // 绿色的
  6.   // ... 这里接着写设计师提供的所有颜色值
  7. }
  8. class AppDarkColors {
  9.   static const Color demo1 = Colors.black; // 黑色的
  10.   static const Color demo2 = Colors.white; // 白色的
  11.   // ... 这里接着写设计师提供的所有颜色值
  12. }
复制代码
2. 定义我们自己的Theme

接着,我们就要创建我们自己的Theme了,通过ThemeExtension来实现,这里有几点需要注意:

  • 如果颜色值很多(基本都会很多),尽量使用ai来帮你实现复制粘贴内容,这里的颜色值需要完完整整的都定义出来,跟着设计师给出的颜色表。
  • lerp方法是一个渐变方法,切换主题后,所有颜色会有一个渐变效果,很好看。可以直接使用Color.lerp方法进行。
    例如:
  1. import 'package:flutter/material.dart';
  2. /// app_colors_extension.dart
  3. class AppColorsExtension extends ThemeExtension {
  4.   AppColorsExtension({
  5.     required this.demo1,
  6.     required this.demo2,
  7.     // ... 这里需要定义所有的值,如果写的累就找AI吧
  8.   });
  9.   final Color demo1; // 演示值1
  10.   final Color demo2; // 演示值2
  11.   // ... 这里需要定义所有的值,如果写的累就找AI吧
  12.   @override
  13.   ThemeExtension copyWith({Color? demo1, Color? demo2}) {
  14.     return AppColorsExtension(
  15.       demo1: demo1 ?? this.demo1,
  16.       demo2: demo2 ?? this.demo2,
  17.       // ... 这里需要定义所有的值,如果写的累就找AI吧
  18.     );
  19.   }
  20.   @override
  21.   ThemeExtension lerp(
  22.     ThemeExtension? other,
  23.     double t,
  24.   ) {
  25.     // 这里排除了不是我们自定义的情况
  26.     if (other is! AppColorsExtension) {
  27.       return this;
  28.     }
  29.     return AppColorsExtension(
  30.       demo1: Color.lerp(demo1, other.demo1, t)!,
  31.       demo2: Color.lerp(demo2, other.demo2, t)!,
  32.       // ... 这里需要定义所有的值,如果写的累就找AI吧
  33.     );
  34.   }
  35. }
复制代码
3. 写我们的Theme吧

前两步,我们定义好了ThemeExtension和Color,现在,通过自定义的theme,我们把ThemeExtension和Color绑定在一起。
例如:
  1. import 'package:flutter/material.dart';
  2. import 'app_colors.dart';
  3. import 'app_colors_extension.dart';
  4. /// app_themes.dart
  5. // 我们自定义的亮色主题
  6. class LightTheme {
  7.   static ThemeData theme = ThemeData.light().copyWith(
  8.     extensions: [_lightAppColors],
  9.   );
  10.   static final _lightAppColors = AppColorsExtension(
  11.     demo1: AppLightColors.demo1,
  12.     demo2: AppLightColors.demo2,
  13.   );
  14. }
  15. // 我们自定义的暗色主题
  16. class DarkTheme {
  17.   static ThemeData theme = ThemeData.dark().copyWith(
  18.     extensions: [_darkAppColors],
  19.   );
  20.   static final _darkAppColors = AppColorsExtension(
  21.     demo1: AppDarkColors.demo1,
  22.     demo2: AppDarkColors.demo2,
  23.   );
  24. }
复制代码
4. 把自定的Theme配置到MaterialApp中

上一步中我们写好了亮色主题和暗色主题,那么我们把这个主题绑定到Flutter的项目中。
例如:
  1. import 'package:flutter/material.dart';
  2. import 'home_page.dart';
  3. import 'app_themes.dart';
  4. /// main.dart
  5. void main() {
  6.   runApp(const MyApp());
  7. }
  8. class MyApp extends StatefulWidget {
  9.   const MyApp({super.key});
  10.   @override
  11.   State<MyApp> createState() => _MyAppState();
  12. }
  13. class _MyAppState extends State<MyApp> {
  14.   ThemeMode _themeMode = ThemeMode.light; // 默认设置为light
  15.   // 这里定义一个切换主题的方法,提供给HomePage使用,这里看大家的状态管理框架要怎么处理了
  16.   void toggleTheme() {
  17.     setState(() {
  18.       _themeMode = _themeMode == ThemeMode.light
  19.           ? ThemeMode.dark
  20.           : ThemeMode.light;
  21.     });
  22.   }
  23.   @override
  24.   Widget build(BuildContext context) {
  25.     return MaterialApp(
  26.       title: 'Flutter Theme Demo',
  27.       theme: AppLightTheme.theme, // 这里定义亮色主题
  28.       darkTheme: AppDarkTheme.theme, // 这里定义暗色主题
  29.       themeMode: _themeMode, // 设置主题模式,这里就要看大家的状态管理框架要怎么处理了
  30.       home: HomePage(toggleTheme: toggleTheme),
  31.     );
  32.   }
  33. }
复制代码
5. 用起来用起来

至此,我们所有的配置工作就全部做完了,现在,就开始用起来。
获取颜色的方法:Theme.of(context).extension()?.demo1
例如:
  1. import 'package:flutter/material.dart';
  2. import 'app_colors_extension.dart';
  3. /// home_page.dart
  4. class HomePage extends StatelessWidget {
  5.   const HomePage({super.key, required this.toggleTheme});
  6.   final void Function() toggleTheme;
  7.   @override
  8.   Widget build(BuildContext context) {
  9.     return Scaffold(
  10.       appBar: AppBar(title: Text('Flutter Theme Demo')),
  11.       body: Center(
  12.         child: Column(
  13.           mainAxisAlignment: .center,
  14.           children: [
  15.             Container(
  16.               decoration: BoxDecoration(
  17.                 color: Theme.of(
  18.                   context,
  19.                 ).extension()!.demo1, // 这里就是使用我们自定义的颜色
  20.                 border: Border.all(width: 1, color: Colors.grey),
  21.               ),
  22.               height: 120,
  23.               width: 120,
  24.             ),
  25.             Container(
  26.               decoration: BoxDecoration(
  27.                 color: Theme.of(
  28.                   context,
  29.                 ).extension()?.demo2, // 这里就是使用我们自定义的颜色
  30.                 border: Border.all(width: 1, color: Colors.grey),
  31.               ),
  32.               height: 120,
  33.               width: 120,
  34.             ),
  35.             ElevatedButton(
  36.               onPressed: () {
  37.                 // 点击这里切换主题, 从light切换到dark, 从dark切换到light
  38.                 toggleTheme();
  39.               },
  40.               child: Text("切换主题"),
  41.             ),
  42.           ],
  43.         ),
  44.       ),
  45.     );
  46.   }
  47. }
复制代码
这样,我们的代码就都写好啦。
6. 来看看效果

这就是效果咯,来看一下,感受一下
浅色深色动画效果
1.png
2.png
3.gif
7. 一点点简化的小方法

我们看到,第5步中,获取颜色的方法Theme.of(context).extension()?.demo1,写起来有点长,我们来化简一下:
例如:
首先,得修改一下app_themes.dart文件,来提供默认的颜色
  1. // ......
  2. // 我们自定义的亮色主题
  3. class AppLightTheme {
  4.   static ThemeData theme = ThemeData.light().copyWith(
  5.     extensions: [lightAppColors], // <-- 改了这里,把下划线去掉,变为public字段
  6.   );
  7.   // 改了这里,把下划线去掉,变为public字段
  8.   static final lightAppColors = AppColorsExtension(
  9.     demo1: AppLightColors.demo1,
  10.     demo2: AppLightColors.demo2,
  11.   );
  12. }
  13. // ......
复制代码
这时,我们调用的时候,可以使用Theme.of(context).appColors.demo1来进行。
例如:
[code]import 'package:flutter/material.dart';import 'theme_extension.dart'; // 这里就需要引入这个类来使用我们的简化方法// import 'app_colors_extension.dart';

相关推荐

您需要登录后才可以回帖 登录 | 立即注册