展开菜单
首页 精品内容 本月促销 装机必备 Windows macOS软件 IOS软件 Android AI PDF教程 专题
全部分类

当前位置:

首页 > 编程开发 > flutter中如何使用和扩展ThemeData实现详解

flutter中如何使用和扩展ThemeData实现详解

Flutter使用ThemeData统一管理颜色、字体等主题配置,在MaterialApp的theme属性中注册,子控件通过Theme.of(context)读取。可通过extension扩展ThemeData添加自定义字段,再利用Provider封装ThemeData并通知主题变更,实现一键换肤功能。

前言

做过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 类,能帮我们省掉手动封装常量配置类的步骤。把色值、字体风格等存入 ThemeData,子控件统一通过 Theme.of(context) 读取各项配置。

这篇通过一个换肤 Demo,聊聊如何在 Flutter 项目中使用 Theme,以及如何对 ThemeData 进行字段扩展,实现全局主题配置管理。

Theme 的基本使用方式

1. Theme 的注册

MaterialApp(
  theme: myThemeData, //一个ThemeData的实例,下面提供具体代码
  home: BodyWidget(),
)

做全局主题配置,只需要在 MaterialApp 的 theme 字段传入一个 ThemeData 实例。myThemeData 就是实现实例,可以通过 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 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 的构造函数可以看到,它内置的字段是有限的。如果 UI 设计包含的色值或字体样式数量超出了 ThemeData 的可设置范围,该怎么办?

比如想新增一个色值配置,叫 connerColor,并且希望保持统一,全部通过 ThemeData 来读取和配置。怎么处理?

常见的做法是:将 ThemeData 封装一层,以新增 connerColor 为例。具体代码结合下面的一键换肤一起看。

如何实现一键换肤

有了 ThemeData 作为统一的管理配置后,实现一键换肤的思路就很清晰了:

flutter中如何使用和扩展ThemeData实现详解

除了 ThemeData 存放配置信息,还需要一个监听类来通知主题变更。这里用 provider 来实现。

1. 首先在 yaml 新增引入 provider

dependencies:
  provider: ^6.0.2

2. 创建主题枚举

假设提供两种主题切换:

///主题类型
enum ThemeEnum {
  yellow,
  red,
}

3. ThemeData 进行一层封装处理

对 ThemeData 封装一层,添加 connerColor 扩展字段:

///自定义模型,包装一下 themeData
class ThemeItem {
  final ThemeEnum themeEnum;
  final ThemeData themeData;
  // 扩展一个字段,用于表示自定义色值
  final Color connerColor;
  ThemeItem(
    this.themeEnum,
    this.themeData, {
    required this.connerColor,
  });
}

4. 创建一个主题管理类 ThemeConfig

abstract class ThemeConfig {
  ///记录当前选中主题
  static late ThemeItem _currentTheme;
  static ThemeData get currentThemeData => _currentTheme.themeData;
  static ThemeEnum get currentTheme => _currentTheme.themeEnum;
  ///提供获取扩展的色值
  static Color? get connerColor => _currentTheme.connerColor;
  ///设置选中主题,提供外部调用,更换当前主题
  static void initTheme(ThemeItem theme) {
    _currentTheme = theme;
  }
}

5. 通过 ThemeData 进行读取保持统一

为了保持统一,仍然通过 ThemeData 读取,使用 extension 对新增字段 connerColor 进行扩展:

extension ExTheme on ThemeData {
  ///扩展获取自定义色值
  Color get connerColor => ThemeConfig.connerColor!;
}

6. 基于 provider 的使用

添加一个工具类,用于通知主题变更:

class AppInfoProvider with ChangeNotifier {
  ThemeData get currentTheme => ThemeConfig.currentThemeData;
  ///切换主题
  setTheme(ThemeItem theme) {
    ThemeConfig.initTheme(theme);
    notifyListeners();
  }
}

切换主题时直接调用:

Provider.of(context, listen: false).setTheme(themeItem);

7. 创建一个主题仓库,里面存放两套主题

///主题仓库
abstract class ThemeStore {
  static List themes = [
    //红色主题
    ThemeItem(
      ThemeEnum.yellow,
      ThemeData(
        primaryColor: Colors.yellow,
        backgroundColor: Colors.yellow,
      ),
      connerColor: Colors.blue,
    ),
    //黄色主题
    ThemeItem(
      ThemeEnum.red,
      ThemeData(
        primaryColor: Colors.red,
        backgroundColor: Colors.red,
      ),
      connerColor: Colors.green,
    ),
  ];
}

8. 完整的 demo 代码及效果

main.dart

void main() {
  ///初始化主题
  ThemeConfig.initTheme(
    ThemeStore.themes.first,
  );
  runApp(const Material(
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider.value(value: AppInfoProvider()),
      ],
      child: Consumer(
        builder: (context, appInfo, _) {
          return MaterialApp(
            theme: appInfo.currentTheme,
            home: Column(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.center,
              children: const [
                BodyWidget(),
                SizedBox(
                  height: 30,
                ),
                _ThemePageButton(),
              ],
            ),
          );
        },
      ),
    );
  }
}

class _ThemePageButton extends StatelessWidget {
  const _ThemePageButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TextButton(
      onPressed: () {
        Na vigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => const ThemeSetWidget(),
          ),
        );
      },
      child: const Text('打开主题设置页面'),
    );
  }
}

body_widget

class BodyWidget extends StatelessWidget {
  const BodyWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 300,
      width: 300,
      //读取标准色值
      color: Theme.of(context).backgroundColor,
      child: Center(
        child: Container(
          height: 100,
          width: 150,
          //读取自定义色值
          color: Theme.of(context).connerColor,
        ),
      ),
    );
  }
}

两个方块:外层方块读取 ThemeData 标准字段色值,内层方块读取扩展字段色值,统一通过 ThemeData 读取。

theme_set_widget

extension ExThemeEnum on ThemeEnum {
  Color get value {
    switch (this) {
      case ThemeEnum.yellow:
        return Colors.yellow;
      case ThemeEnum.red:
        return Colors.red;
    }
  }
}
///主题选择页面
class ThemeSetWidget extends StatelessWidget {
  const ThemeSetWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("颜色主题"),
        backgroundColor: Theme.of(context).backgroundColor,
      ),
      body: ExpansionTile(
        leading: const Icon(Icons.color_lens),
        title: const Text('颜色主题'),
        initiallyExpanded: true,
        children: [
          Padding(
            padding: const EdgeInsets.only(
              left: 10,
              right: 10,
              bottom: 10,
            ),
            child: Wrap(
              spacing: 8,
              runSpacing: 8,
              children: ThemeStore.themes
                  .map((e) => _createItemWidget(context, e))
                  .toList(),
            ),
          )
        ],
      ),
    );
  }

  Widget _createItemWidget(
    BuildContext context,
    ThemeItem theme,
  ) {
    return InkWell(
      onTap: () {
        Provider.of(context, listen: false).setTheme(theme);
      },
      child: Container(
        width: 40,
        height: 40,
        color: theme.themeEnum.value,
        child: ThemeConfig.currentTheme == theme.themeEnum
            ? const Icon(
                Icons.done,
                color: Colors.white,
              )
            : null,
      ),
    );
  }
}

flutter中如何使用和扩展ThemeData实现详解

本文内容来源于网友投稿,如有侵权请联系删除。
作者最新文章
编程开发
相关文章 更多
精品专题 更多
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

IOS软件

正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

AI

正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

Mac软件 更多
Blender
Blender

Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

灵活计算器
灵活计算器

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

图几
图几

图几是一款适用于 macOS 的截图、标注与美化工具,支持离线操作保障隐私。界面整理和高频系统操作被放到一起考虑,桌面或窗口内容一多时,管理起来会更省心。

密码键盘
密码键盘

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

思源笔记
思源笔记

思源笔记是一款本地笔记软件,提供所见即所得的编辑方式,为长文写作带来顺滑的体验。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

Office 365 简体中文
Office 365 简体中文

一款文字处理软件,一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将 Excel 和 Outlook 等应用与 OneDrive 和 Microsoft Teams 等强大的云服务相结合,Office 365 可让任何人使用任何设备随时随地创建和共享内容。

Mac
WALTR PRO
WALTR PRO

WALTR是一款电脑至iOS文件传输转换工具,操作简单,快速实现文件识别与传送。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

CodeExpander
CodeExpander

CodeExpander 是一款快捷短语输入增强工具,通过键入缩写自动展开为自定义文段,提升工作效率。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。

Mountain Duck
Mountain Duck

Mountain Duck 是一款能将多个网盘挂载到本地的工具,像本地磁盘一样使用网盘。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

Menuist
Menuist

Menuist 是一款面向 macOS 的 Finder 右键菜单增强工具,主要用来补充新建文件、快捷导航等常用操作,让日常文件管理和访问路径时更高效、更顺手。

WINDOWS 更多
Blender
Blender

Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

Windows 10
Windows 10

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

思源笔记
思源笔记

思源笔记是一款本地笔记软件,提供所见即所得的编辑方式,为长文写作带来顺滑的体验。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

傲梅轻松备份
傲梅轻松备份

傲梅轻松备份是一款专业易用的数据备份软件,为重要数据提供安全保障。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

Office 365 简体中文
Office 365 简体中文

一款文字处理软件,一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将 Excel 和 Outlook 等应用与 OneDrive 和 Microsoft Teams 等强大的云服务相结合,Office 365 可让任何人使用任何设备随时随地创建和共享内容。

Mac
Wise Folder Hider Pro
Wise Folder Hider Pro

Wise Folder Hider Pro 是一款专业级文件和文件夹隐藏加密软件,为私密数据添加多重保护。高频操作更强调就近处理,浏览、整理和跨目录移动文件时,来回切换和重复点击都会少很多。

WALTR PRO
WALTR PRO

WALTR是一款电脑至iOS文件传输转换工具,操作简单,快速实现文件识别与传送。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

CodeExpander
CodeExpander

CodeExpander 是一款快捷短语输入增强工具,通过键入缩写自动展开为自定义文段,提升工作效率。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。

PinStack
PinStack

PinStack是一款轻量级的Windows平台剪贴板管理工具,优化您的剪贴板使用体验。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

Mountain Duck
Mountain Duck

Mountain Duck 是一款能将多个网盘挂载到本地的工具,像本地磁盘一样使用网盘。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。