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 为例,具体代码结合下面

(0)

相关推荐

  • flutter InheritedWidget使用方法总结

    目录 引言 didChangeDependencies 如何使用? 结论 引言 InheritedWidget,flutter中非常重要的一个功能组件.比如我们在应用的根 widget 中通过InheritedWidget共享了一个数据,那么我们便可以在任意子 widget 中来获取该共享的数据. didChangeDependencies 说到 InheritedWidget ,我们不得不聊聊 state 对象中的 didChangeDependencies 方法.当子控件依赖使用了父控件中的

  • Flutter改变状态变量是否必须写在setState回调详解

    正文 我们都知道 setState(VoidCallback fn) 是这样用的: setState(() { count++; }); 执行完后组件会重新 build(),就可以取到 count 的最新值了.但其实这样写也是一样的: count++; setState(() {}); 因为 setState() 最后会调用 markNeedsBuild(),Flutter 会调度使组件 rebuild,所以状态变量的改变不是必须写在 setState() 的回调里面,只需要最后执行一下 set

  • Flutter 状态管理scoped model源码解读

    目录 一.什么是 scoped_model 二.用法 三.实现原理 四.结束 一.什么是 scoped_model 本文主要从 scoped_model 的简单使用说起,然后再深入源码进行剖析(InheritedWidget.Listenable.AnimatedBuilder),不会探讨 Flutter 状态管理的优劣,单纯为了学习作者的设计思想. scoped_model 是一个第三方 Dart 库,可以让您轻松的将数据模型从父 Widget 传递到子 Widget.此外,它还会在模型更新时

  • 使用PlatformView将 Android 控件view制作成Flutter插件

    目录 引言 1. FlutterPlugin 创建 2. 创建 Android 控件 3. 注册 Android 控件 4. 封装 Android 层通信交互 ‘CustomViewController’ 代码说明 5. 在 flutter 中如何使用已注册的 Android 控件(view) 代码说明 如何使用这个View 6. 附上 example 完整代码 引言 小编最近在项目中实现相机识别人脸的功能,将 Android 封装的控件 view 进行中转,制作成 FlutterPlugin

  • Flutter 绘制风车实现示例详解

    目录 前言展示 1. 风车 1 的绘制 2. 风车 2 的绘制 3. 旋转动画的处理 4. 旋转动画的圈数 前言展示 最近源码看得比较多,本文来画点东西调节下心情,本绘制已收录于 FlutterUnit 的绘制集录,本文源码可参见[windmill.dart] .绘制内容非常简单,如下所示,两个样式的小风车:通过这两个小例子,可以学到: 路径的使用 画板的旋转变换 动画曲线与 Tween 的使用 风车1 风车2 1. 风车 1 的绘制 第一个风车非常简单,由四个 半圆 组成,每个部分直接的关系是

  • flutter Bloc 更新后事件同步与异步详解

    目录 前言 使用方式 Bloc 新形态用法 事件队列的阻塞属性? 前言 最近,小轰参与了公司 flutter 项目关于 Dart 2.0 的空安全升级工作.我们升级了所有依赖的三方库,其中就包括有 Bloc 库.作为一款使用率颇高的状态管理框架, Bloc 在版本迭代中进行了少许结构和细节的优化,下面是小轰对于 Bloc 新版本的使用总结. 使用方式 小轰使用的 Bloc 版本如下 flutter_bloc: ^7.3.1 通过最简单的例子来学习新知识 创建一个包含 加 减 操作的页面,使用 b

  • Flutter中如何实现无Context跳转详解

    背景介绍 Navigator.of(context).push(MaterialPageRoute(builder: (context){ return DemoPage(); })); 在日常的项目开发中,我们一般push一个新页面是用上面的方法的,利用Navigator.of(context)来进行push或者pop操作. 缺点:这种情况是必须传context的,目的是为了利用Navigator.of(context)来获取到NavigatorState对象,然后才能进行push或者pop操

  • Flutter在项目中使用动画不使用包实现详解

    目录 前言 正文 1 按下按钮柔软的感觉 2 想要一个像 Instagram 一样的喜欢按钮吗? 3 动画页面过渡 4 动画文字 5 更改/闪动文本样式 前言 动画对于 web 和移动应用程序都非常重要.但是在移动应用程序中不应该使用夸张的动画.简单但是很多动画使你的应用程序更好用.以至于当你点击一个按钮时,一种平滑的感觉或者页面过渡都会影响到你. 正文 1 按下按钮柔软的感觉 class _CustomButtonState extends State<CustomButton> with

  • Flutter封装组动画混合动画AnimatedGroup示例详解

    目录 一.来源 二.AnimatedGroup使用示例: 三.AnimatedGroup源码 最后 一.来源 项目中遇到混合动画的情况,每次实现都需要生命一堆属性,让代码变得杂乱,难以维护. 参考 iOS 组动画 CAAimationGroup, 随花半天时间封装一个混合动画组件 AnimatedGroup. 此组件基于极简.高扩展.高适用的封装原则,基本满足当前项目开发. 二.AnimatedGroup使用示例: // // AnimatedGroupDemo.dart // flutter_

  • Spring jdbc中数据库操作对象化模型的实例详解

    Spring jdbc中数据库操作对象化模型的实例详解 Spring Jdbc数据库操作对象化 使用面向对象方式表示关系数据库的操作,实现一个线程安全可复用的对象模型,其顶级父类接口RdbmsOperation. SqlOperation继承该接口,实现数据库的select, update, call等操作. 1.查询接口:SqlQuery 1) GenericSqlQuery, UpdatableSqlQuery, MappingSqlQueryWithParameter 2) SqlUpda

  • Android 中CheckBox的isChecked的使用实例详解

    Android 中CheckBox的isChecked的使用实例详解 范例说明 所有的网络服务在User使用之前,都需要签署同意条款,在手机应用程序.手机游戏的设计经验中,常看见CheckBox在同意条款情境的运用,其选取的状态有两种即isChecked=true与isChecked=false. 以下范例将设计一个TextView放入条款文字,在下方配置一个CheckBox Widget作为选取项,通过Button.onClickListener按钮事件处理,取得User同意条款的状态. 当C

  • PHP7.1中使用openssl替换mcrypt的实例详解

    在php开发中,使用mcrypt相关函数可以很方便地进行AES加.解密操作,但是PHP7.1中废弃了mcrypt扩展,所以必需寻找另一种实现.在迁移手册中已经指出了用openssl代替mcrypt,但未给出具体示例.网上有很多示例,可以替换大部分场景,但对于其中细节却并未说明.同样,简单地使用网上示例在某种代码场景下有可能导致代码替换前后的兼容问题,以下则来谈谈具体代码及原因. 首先我们直接给出替换的代码,再从代码中分析问题.(本文中分析的算法是AES-128-CBC) 替换示例 示例会展示两种

  • JS中实现浅拷贝和深拷贝的代码详解

    (一)JS中基本类型和引用类型 JavaScript的变量中包含两种类型的值:基本类型值 和 引用类型值,在内存中的表现形式在于:前者是存储在栈中的一些简单的数据段,后者则是保存在堆内存中的一个对象. 基本类型值 在JavaScript中基本数据类型有 String , Number , Undefined , Null , Boolean ,在ES6中,又定义了一种新的基本数据类型 Symbol ,所以一共有6种. 基本类型是按值访问的,从一个变量复制基本类型的值到另一个变量后,这两个变量的值

  • 对Django中内置的User模型实例详解

    User模型 User模型是这个框架的核心部分.他的完整的路径是在django.contrib.auth.models.User. 字段 内置的User模型拥有以下的字段: 1.username: 用户名.150个字符以内.可以包含数字和英文字符,以及_.@.+..和-字符.不能为空,且必须唯一! 2.first_name:歪果仁的first_name,在30个字符以内.可以为空. 3.last_name:歪果仁的last_name,在150个字符以内.可以为空. 4.email:邮箱.可以为空

  • Mac下关于PHP环境和扩展的安装详解

    一直使用windows和Centos进行开发,之前公司配了Mac本,放家里吃灰了一年,新公司还是Mac,无奈只好从头摸索. php安装主要使用brew,请注意 由于git上原homebrew/php已经停掉,新的均迁移到到brew/core上,因此之前的安装方法无法使用,请注意!!!!! 安装php等操作均使用以下步骤: 1.搜索可用php版本 brew search php 2.安装指定的php版本 brew install php@7.1 3.启动php或停止php服务 brew servi

  • python程序文件扩展名知识点详解

    python程序文件的扩展名称是什么 python程序的扩展名有.py..pyc..pyo和.pyd..py是源文件,.pyc是源文件编译后的文件,.pyo是源文件优化编译后的文件,.pyd是其他语言写的python库. 扩展名 在写Python程序时我们常见的扩展名是py, pyc,其实还有其他几种扩展名.下面是几种扩展名的用法. py:py就是最基本的源码扩展名.windows下直接双击运行会调用python.exe执行. pyw:pyw是另一种源码扩展名,跟py唯一的区别是在windows

随机推荐