Flutter 小技巧之 3.16 升级最坑 M3 默认适配技巧

如果要说 Flutter 3.16 升级里是最坑的是什么?那我肯定要说是 Material 3 default (M3)。

倒不是说 M3 bug 多,也不是 M3 在 3.16 上使用起来多麻烦,因为虽然从 3.16 开始,MaterialApp 里的 useMaterial3 默认会是 true,但是你是可以直接 使用 useMaterial3: false 来关闭

那为什么还收坑?因为未来 Material 2 相关的东西会被弃用并删除,所以 Material 3 default(M3) 是一个警告,你可以通过 useMaterial3: false 来关闭无视,但是这个技术债未来会很坑。

难道你还能一直苟着不更新?

为什么说它很坑?因为适配它纯纯是一个体力活,而且还是一个细节工作,M3 是一套配色方案,一套和 M2 「毫不相关」的配色方案

  • 配色方案代表着它已经帮你默认确定了什么地方应该用什么颜色
  • M2 毫不相干,代表着你之前用这 M2 的 Widget 默认的 UI 效果,用了 M3 会完全不一样

如上图所示,看起来好像是就是:

  • AppBar 配色发生了变化
  • FloatingActionButton 从圆的变成方的,颜色发生变化
  • 默认 Button 按照风格发生了变卦
  • ······

似乎看起来也没什么,但是你知道有多少地方用了 FloatingActionButton ?每个地方的 AppBar 难道都要手动去调整?ElevatedButtonTextButton 有没有办法全局配置?本篇就是为了让你少走适配弯路,提供适配思路的角度。

核心还是国内的产品有谁愿意使用 Material Design ? 像这种 M2 到 M3 的变化,对于开发者来说纯粹就是负优化。

开始

首先,官方 Material 3 配色首推是使用 ColorScheme.fromSeed() 来生成配色,当然你也可以通过 ColorScheme.fromImageProvider 的图片来生成配色,不过一般人应该不会这么干,另外还有 ColorScheme.fromSwatch ,不过这个的灵活适配程度不如 fromSeed,所以使用 fromSeed 是比较好的选择。

因为 M3 默认从蓝色系列变成紫色系统,所以如果你用的是默认色系,那就更需要配置来恢复,本篇的目的就是,让 App 在 M3 下恢复到 M2 的 UI 效果,因为它真的不是仅仅一个颜色变化而已。

如果你以前的 ThemeData 是如下所示代码,那么运行之后你会看到,原本应该是 M2 效果的正常列表,现在变成了 M3 那种「无法言喻」的效果,可以看到此时 M3 下 primarySwatch 其实并没有起到作用。

ThemeData(
  primarySwatch: Colors.blue,
  
)
  
M2M3

那么首先我们要做的就是增加 colorScheme ,但是你在加完会发现并没有什么变化,这是因为此时控件还是处于 M3 的色系下,所以接下来我们要首先全局恢复 Appbar

ThemeData(
  primarySwatch: Colors.blue,
  colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),

Do it。

AppBar

如下代码所示,我们先添加 AppBarTheme ,可以看到 AppBar 的背景这样就变回了蓝色,但是这时候 Appbar 的文本和图标还是黑色。

ThemeData(
  primarySwatch: Colors.blue,
  colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),

  appBarTheme: AppBarTheme(
    backgroundColor: Colors.blue,
  ),
),

为了让图标和文本恢复到 M2 的白色,我们可以在 AppBarTheme 里配置 iconThemetitleTextStyle ,可以看到配置后如下图所示,UI 上 AppBar 已经恢复到 M2 的效果,那么此时你可以会疑惑,为什么修改的配置是 size: 24.0Typography.dense2021.titleLarge

AppBarTheme(
  iconTheme: IconThemeData(
    color: Colors.white,
    size: 24.0,
  ),
  backgroundColor: Colors.blue,
  titleTextStyle:  Typography.dense2014.titleLarge,
)

其实这就是本篇的核心:在 M2 控件还没被剔除的时候,通过参考源码将 M3 UI 恢复到 M2

例如在 3.16 的源码里,theme.useMaterial3 ? 这样的代码目前随处可见,而此时 AppBar 里:

  • _AppBarDefaultsM3 下 icon 的颜色是通过 onSurface 字段,大小是 24
  • _AppBarDefaultsM2 下 icon 是直接使用 theme 下默认的样式,也就是 size 24, 颜色白色。

M2M3

所以我们可以在上面的 IconThemeData 里可以直接配置 color: Colors.white, size: 24.0, 来恢复到 M2 的效果。

当然你也可以配置 ColorSchemeonSurface 来改变颜色,但是这个影响返回太大,还是推荐配置 AppBarThemeIconThemeData

另外可以看到,此时还有一个 Typography.dense2014.titleLarge ,这又是哪里来的?还是回到_AppBarDefaultsM3 里,在 M3 下, AppBar 使用的是 ThemeData 下的 textTheme.titleLarge ,而默认字体样式配置,基本来自 Typography 对象。

Typography 里默认配置了大量字体配置,例如 Typography.dense2014 对应就是如下所示配置,从上面代码可以看到默认情况下 M2 用的是 Typography.material2014 ,对应就是 Typography.dense2014,也就是在 AppBar 上 Typography.dense2014.titleLarge 就可以让 M3 的 AppBar 文本恢复到 M2 的样式。

看到这里你是否已经学会了大概的思路?

通过 theme.useMaterial3 去检索控件,然后在源码里找到 M2 的实现,然后将其修改到全局的主题设置里,比如 AppBar 的就通过 AppBarTheme 配置,如果是 M2 的实现又引用了某些默认配置,就去检索这些默认配置的起源,所以说 M3 这个坑是一个体力活。

当然,这个思路下,有一些控件适配起来还是会有坑,因为它的变化确实有点大,例如 Card 控件。

Card

如图所示,这是 Card 控件在 M2 和 M3 下的变化,除了默认弧度之后,最主要就是颜色发生了改变,从默认白色变成了带着浅蓝色的效果,但是这里有个坑,就是,此时就算你给 Card 设置 color: Colors.white, ,它也依旧会带着这个浅蓝色的效果

M2M3

那么这个颜色如何去除?其实只要 ColorScheme 下设置 surfaceTint 为透明色就可以了,如下图所示,因为 Card 的效果是通过封装 Material 控件实现,而 Material 在 M3 下会通过 elevationsurfaceTint 去合成一个覆盖色。

ColorScheme.fromSeed(
  seedColor: Colors.blue,

  ///影响 card 的表色,因为 M3 下是  applySurfaceTint ,在 Material 里
  surfaceTint: Colors.transparent,
),

所以根据判断,surfaceTint 设置成透明就可以去除 Card 这个覆盖色,这个逻辑在 BottomAppBar 里同样存在,所以如果你需要把它们都恢复都 M2 效果,那么就只需要把 surfaceTint 设置成透明色即可。

image-20231123172627998

所以类似的变动才是 M3 里最坑的点,如果你不了解他们的底层实现,那么在升级之后,发现明明代码给了白色,为什么它还是会有浅蓝色效果?这对于开发者来就是一个找🐛的天坑,所以在这里也用 Card 提供一个解决问题的典型思路。

另外还有一个典型的控件,那就是 FloatingActionButton(FAB) 。

FloatingActionButton

从 M2 到 M3, FloatingActionButton(FAB) 控件最大的变化就是变成了方形,其次颜色也不跟随之前和主题蓝色,我们不说 M3 这个「优化」如何,就说如何恢复到 M2 的效果。

M2M3

首先按照惯例,肯定有一个叫 floatingActionButtonTheme 的参数,可以用于配置 FloatingActionButtonThemeData ,所以这里我们首先添加上配置,然后通过 shape 先变回原形,并且修改 backgroundColor 变成蓝色。

floatingActionButtonTheme: FloatingActionButtonThemeData(
    backgroundColor: Colors.blue,
    shape: CircleBorder()
),

那么此时剩下的就是 Icon 的颜色,我们当然可以在用到 Icon 的地方手动修改为白色,但是我们希望的是全局配置默认恢复到 M2 时代,所以我们就要去找 FAB 下 Icon 是如何获取到颜色的。

而寻找这个颜色的实现,居然就让我开启了一段漫长的旅程·····

首先 Icon 肯定是通过 IconThemeData 去获取默认颜色,因为 FAB 的主题下没有 iconTheme 可以配置,那么首先就想到配置一个全局的 iconTheme: IconThemeData ,但是神奇的问题来了,配置之后居然无效。

那么就开始往上查找,然后依次返现, FAB 内部是通过 RawMaterialButton 实现的点击,而 RawMaterialButton 内部就有一个 IconTheme.merge 的实现,那么 FAB 里的 Icon 默认应该是使用了 effectiveTextColor 这个颜色

之后开始经历一番漫长检索关联,最终可以看到:

  • 这个 effectiveTextColor 来自从 FAB 传入的 TextSytle 的 color
  • textSytle 来自 extendedTextStyle
  • extendedTextStyle 来自 foregroundColor
  • foregroundColor 默认来自 floatingActionButtonThemeforegroundColor

image-20231123174431747

所以破案了,需要全局设置 FAB 下 Icon 的颜色,是要配置 FloatingActionButtonThemeDataforegroundColor ,这个设定和名称正常情况下谁能想得到呢?

而且这个传递嵌套如此“隐晦”,只能说, FAB 是 Flutter 样式跟踪里很典型的一个代表:传递深,theme 引用复杂,类似 merge/copy 的局部实现太过隐蔽

floatingActionButtonTheme: FloatingActionButtonThemeData(
    backgroundColor: Colors.blue,
    foregroundColor:  Colors.blue,
    shape: CircleBorder()),

另外关于 IconThemeData 还有一个冷知识,参数不全的情况下,也就是不满足 isConcrete 的情况下,其他的参数在 of(context) 的时候是会被 fallback 覆盖,这个对于 M3 - M2 的降级适配里也是一个关键信息。

primarySwatch

最后在聊一个 ThemeDataprimarySwatch,为什么聊它,因为如果你的代码里用了 primaryColorDarkprimaryColorLight 作为配置,那么使用 ColorScheme.fromSeed 之后,它们会发生一些「奇妙的变化」,所以为了它们可以恢复到 M2 模式,那么设置 primarySwatch 可以将它们恢复到原有的效果。

最后

如下所示是本次升级适配里的示例代码总和,其实 M3 模式下「降级」到 M2 UI 效果真的是一个体力活,类似上面三个典型的例子,都可以看出来跟踪默认 UI 的实现并不轻松,虽然对于 Flutter 团队来说,升级到 M3 可能是一次正向优化,但是对于不喜欢 Material Design 的国区而言,M3 只能是一个负优化,不知道大家同意不?

return ThemeData(
  ///用来适配 Theme.of(context).primaryColorLight 和 primaryColorDark 的颜色变化,不设置可能会是默认蓝色
  primarySwatch: color as MaterialColor,

  /// Card 在 M3 下,会有 apply Overlay

  colorScheme: ColorScheme.fromSeed(
    seedColor: color,
    primary: color,

    brightness: Brightness.light,

    ///影响 card 的表色,因为 M3 下是  applySurfaceTint ,在 Material 里
    surfaceTint: Colors.transparent,
  ),

  /// 受到 iconThemeData.isConcrete 的印象,需要全参数才不会进入 fallback
  iconTheme: IconThemeData(
    size: 24.0,
    fill: 0.0,
    weight: 400.0,
    grade: 0.0,
    opticalSize: 48.0,
    color: Colors.white,
    opacity: 0.8,
  ),

  ///修改 FloatingActionButton的默认主题行为
  floatingActionButtonTheme: FloatingActionButtonThemeData(
      foregroundColor: Colors.white,
      backgroundColor: color,
      shape: CircleBorder()),
  appBarTheme: AppBarTheme(
    iconTheme: IconThemeData(
      color: Colors.white,
      size: 24.0,
    ),
    backgroundColor: color,
    titleTextStyle: Typography.dense2014.titleLarge,
    systemOverlayStyle: SystemUiOverlayStyle.light,
  ),

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/183488.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Shell循环:for(一)

语法结构: for 变量名 [ in 取值列表] do 循环体 done 示例1: 1、需求:自动循环创建10个用户 2、演示: [rootlocalhost ~]# vim for.sh #脚本编写 #!/bin/bash for i in {1..10} do useradd "user$…

探究Kafka原理-2.Kafka基本命令实操

👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理🔥如果感觉博主的文章还不错的话,请&#x1f44…

csv文件添加文件内容和读取

append content to file import numpy as np acc_listnp.array([0.97,0.92,0.93,0.89]) # 注意这个地方添加文件不需要特别声明是什么文件 file open("result.csv", "a") print("{:.2f}, {:.2f}".format(acc_list.mean(), acc_list.std()), f…

服务器安全如何保障

主机安全是指保护计算机主机(也称为服务器、终端或主机设备)免受潜在的安全威胁和攻击的一系列措施和实践。主机安全旨在防止未经授权的访问、数据泄露、恶意软件感染和其他安全漏洞的利用,主机一旦被黑客入侵,企业会面临很多安全…

buck降压电路

一、Buck电路的拓扑结构 Buck是直流转直流的降压电路,下面是拓扑结构,作为硬件工程师,这个最好是能够记下来,了然于胸。 为啥要记下来,自然是因为这个电路太基础了,并且谁都会用到,更重要的一点,面试可能会考。。。 上图是个异步buck,同步buck就是将里面的二极管换成M…

手持式无线通信频谱分析仪 MS2713E

MS2713E 手持式无线通信频谱分析仪 安立手持式无线通信频谱分析仪 MS2713E 旨在处理最恶劣的现场条件,使您能够监控、定位、识别和分析各种蜂窝、2G/3G/4G、陆地移动无线电、Wi-Fi 和广播信号。多功能 Spectrum Master 在定位和识别宽频率范围内的信号时&#xff0…

Java设计模式系列:单例设计模式

Java设计模式系列:单例设计模式 介绍 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法) 比如 Hiberna…

【云原生 Prometheus篇】Prometheus的动态服务发现机制与认证配置

目录 一、Prometheus服务发现的方式1.1 基于文件的服务发现1.2 基于consul的服务发现1.3 基于 Kubernetes API 的服务发现1.3.1 简介1.3.2 基于Kurbernetes发现机制的部分配置参数 二、实例一:部署基于文件的服务发现2.1 创建用于服务发现的文件2.2 修改Prometheus的…

中国毫米波雷达产业分析2——毫米波雷达产业链分析

一、产业链构成 毫米波雷达产业链分为三部分:上游主要包括射频前端组件(MMIC)、数字信号处理器(DSP/FPGA)、高频PCB板、微控制器(MCU)、天线及控制电路等硬件供应商;中游主体是毫米波…

多线程 02

1.线程的常见构造方法 方法说明Thread()创建线程对象Thread(Runnable target)使用 Runnable 对象创建线程对象Thread(String name)创建线程对象,并命名Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名【了解】Thread(Threa…

【Flink】状态管理

目录 1、状态概述 1.1 无状态算子 1.2 有状态算子 2、状态分类 ​编辑 2.1 算子状态 2.1.1 列表状态(ListState) 2.1.2 联合列表状态(UnionListState) 2.1.3 广播状态(BroadcastState) 2.2 按键分…

YOLO目标检测——泄露检测数据集下载分享【含对应voc、coco和yolo三种格式标签】

实际项目应用:泄露检测数据集说明:泄露检测数据集,真实场景的高质量图片数据,数据场景丰富,含多个类别标签说明:使用lableimg标注软件标注,标注框质量高,含voc(xml)、coco(json)和yo…

Python爬虫-获取汽车之家新车优惠价

前言 本文是该专栏的第10篇,后面会持续分享python爬虫案例干货,记得关注。 本文以汽车之家新车优惠价为例,获取各车型的优惠价,示例图如下: 地址:aHR0cHM6Ly9idXkuYXV0b2hvbWUuY29tLmNuLzAvMC8wLzQyMDAwMC80MjAxMDAvMC0wLTAtMS5odG1sI3B2YXJlYWlkPTIxMTMxOTU= 需求:获…

电感热点温度概述及估算方法总结

🏡《电子元器件学习目录》 目录 1,什么是电感的热点温度2,热点温度参数意义3,热点温度计算方法3.1,测温估算法3.2,电阻变化估算法4,总结1,什么是电感的热点温度 电感的热点指电感的发热点,一般是电感的绕阻。电感的热点温度为电感绕阻的温度。 2,热点温度参数意义 电…

JDK11新特性

目录 一、JShell 二、Dynamic Class-File Constants类文件新添的一种结构 三、局部变量类型推断(var ”关键字”) 四、新加的一些实用API 1. 新的本机不可修改集合API 2. Stream 加强 3. String 加强 4. Optional 加强 5. 改进的文件API 五、移…

从0开始学习JavaScript--JavaScript模块化编程

JavaScript模块化编程是现代前端开发中的核心概念之一。通过模块化,能够将复杂的代码分割成独立的模块,提高代码的可维护性、可扩展性,同时实现代码的复用。本文将深入探讨JavaScript模块化的各个方面,包括模块的定义、导入导出、…

YOLOv8改进 | CARAFE既减少参数又提高精度的上采样方法

论文地址:官方论文地址点击即可跳转 代码地址:官方代码地址点击即可跳转 一、本文介绍 本文给大家带来的CARAFE(Content-Aware ReAssembly of FEatures)是一种用于增强卷积神经网络特征图的上采样方法。其主要旨在改进传统的上采…

Springmvc原理解析

1. DispatcherServlet springmvc的核心控制器,负责截获所有的请求,当截获请求后委托给HandlerMapping进行请求映射的解析工作,目的是找到哪一个Controller的方法可以处理该请求,找到后再交由给HandlerAdaptor去负责调用并返回Mod…

RT-Thread 线程间通信【邮箱、消息队列、信号】

线程间通信 一、邮箱1. 创建邮箱2. 发送邮件3. 接收邮件4. 删除邮箱5. 代码示例 二、消息队列1. 创建消息队列2. 发送消息3. 接收消息4. 删除消息队列5. 代码示例 三、信号1. 安装信号2. 阻塞信号3. 解除信号阻塞4. 发送信号5. 等待信号6. 代码示例 一、邮箱 RT-Thread 操作系…

15.Python 异常处理和程序调试

1. 异常处理 异常就是在程序执行过程中发生的超出预期的事件。一般情况下,当程序无法正常执行时,都会抛出异常。 在开发过程中,由于疏忽或考虑不周,出现的设计错误。因此,在后期程序调试中应该根据错误信息&#xff…