flutter中如何使用和扩展ThemeData实现详解
目录
- 前言
- Theme 的基本使用方式
- 1. Theme 的注册
- 2. 读取 ThemeData 里的配置:
- 小技巧介绍
- ThemeData 内置字段不够用,如何扩展?
- 如何实现一键换肤
- 1. 首先在 yaml 新增引入 provider
- 2. 创建主题枚举
- 3. ThemeData 进行一层封装处理
- 4. 创建一个主题管理类 ThemeConfig
- 5. 通过ThemeData进行读取保持统一
- 6. 基于 provider 的使用
- 7. 创建一个主题仓库,里面存放两套主题,用于演示 Demo
- 8.完整的 demo 代码及效果
前言
做过UI开发的同学都知道,在开发中我们通常会将 文字大小、色值 等内容放在配置文件中,通过统一的管理类来读取(严禁在UI代码中写死)。以便后续调整时不用修改源码,只需要修改配置文件即可。
例如这样:
- 定义常量存放
/// 存放颜色常量 abstract class ColorConfigs { static const Color background = Color(0xFFFF6600); static const Color textHint = Color(0xFFA0A4A7); }
- 通过统一获取
/// GOOD Container( //通过 ColorConfig 获取色值 color: ColorConfigs.background, ) /// BAD Container( //写死 color: Color(0xFFFF6600), )
Flutter为我们提供了Theme类,可以让我们节省封装常量配置类(如上示例中的 ColorConfigs)的步骤。将色值、字体风格等配置内容存入ThemeData中,子控件可统一通过 Theme.of(context)
读取 color、textStyle、等配置信息。
本篇通过换肤demo,介绍在flutter项目中如何使用 theme 以及如何对 themeData 进行字段扩展,实现全局的主题配置管理。
Theme 的基本使用方式
1. Theme 的注册
MaterialApp( theme: myThemeData, //一个ThemeData的实例,下面提供具体代码 home: BodyWidget(), )
我们做全局的主体配置,在 MaterialApp 中对 theme 字段进行入参赋值。示例代码中的 myThemeData 是一个 ThemeData 的实现实例,可通过 ThemeData 的构造方法来查看其可供保存的主体及样式信息,按照各自所需进行参数赋值。
下面是小编在自己项目中用到的ThemeData配置项,定义了各种状态颜色、字体样式、可供参考:
myThemeData:
val myThemeData = ThemeData( primaryColor: Colors.white, disabledColor: const Color(0xffcbced0), backgroundColor: const Color(0xfff3f4f5), hintColor: const Color(0xffe2e5e7), errorColor: const Color(0xffe21a1a), highlightColor: const Color(0xffa7d500), shadowColor: const Color(0xffa0a4a7), selectedRowColor: const Color(0xfff3f4f5), colorScheme: const ColorScheme.light( primary: Colors.white, secondary: Color(0xffa7d500), background: Color(0xfff3f4f5), error: Color(0xffe21a1a), onPrimary: Color(0xff242524), onError: Colors.white, onBackground: Color(0xffe2e5e7), onSecondary: Color(0xff707275), ), textTheme: TextTheme( headline1: TextStyle( fontSize: 17.sp, fontWeight: FontWeight.bold, color: const Color(0xff242524), ), headline2: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.bold, color: const Color(0xff242524), ), ...中间省略 healin3 ~ headline5,只是配置不一样 headline6: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.bold, color: const Color(0xff707275), ), subtitle1: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w500, color: const Color(0xff242524), ), subtitle2: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w500, color: const Color(0xff707275), ), bodyText1: TextStyle( fontSize: 11.sp, fontWeight: FontWeight.normal, color: const Color(0xff242524), ), bodyText2: TextStyle( fontSize: 11.sp, fontWeight: FontWeight.normal, color: const Color(0xff242524), ), ), )
2. 读取 ThemeData 里的配置:
@override Widget build(BuildContext context) { return Container( color: Theme.of(context).backgroundColor, child: Text( 'hellow', style: Theme.of(context).headline).bodyText1, ); }
Theme.of(context).backgroundColor
:读取主题配置中的背景颜色,在 myThemeData 中进行过赋值操作Theme.of(context).headline).bodyText1
:读取主题配置中键值为 bodyText1 的字体样式
小技巧介绍
通常为了便于开发阅读,我们也可以使用extension
对 ThemeData 内属性进行重命名获取:
新建 extension_theme.dart,文件名字随意:
///用于重命名颜色属性 extension ThemeDataColorExtension on ThemeData { Color get bgColor => colorScheme.onBackground; ... } ///用于重命名字体样式属性 extension ThemeDataTextStyleExtension on ThemeData { TextStyle get bodyStyle => textTheme.bodyText1!; ... }
在UI页面进行引用导入使用,上面的 demo 可改为:
import ./extension_theme.dart ... @override Widget build(BuildContext context) { return Container( color: Theme.of(context).bgColor, child: Text( 'hellow', style: Theme.of(context).bodyStyle, ); }
ThemeData 内置字段不够用,如何扩展?
从 ThemeData 的构造函数中我们可以看到,ThemeData 内置的字段是有限的。假如我们的UI设计包含的色值数量或者字体样式数量超出了 ThemeData 可供设置数量怎么办呢?
比如:我们想新增一个色值配置,名字就叫 connerColor
,我们还想保持统一,一律通过 ThemeData 来统一读取统一配置,要如何处理呢?
小编在项目里是这么做的,将 ThemeData
进行一层封装,以新增 connerColor
为例,具体代码结合下面