前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >FlutterComponent最佳实践之色彩管理

FlutterComponent最佳实践之色彩管理

作者头像
用户1907613
发布2022-03-31 21:55:09
1.5K0
发布2022-03-31 21:55:09
举报
文章被收录于专栏:Android群英传Android群英传

Flutter中关于色彩和主题的内容非常之多,我们需要理清不同的Color之间的异同,才能更好的开发Flutter应用。

MaterialColor

在ThemeData的构造函数中,我们可以发现两个很有意思的属性

代码语言:javascript
复制
MaterialColor? primarySwatch,
Color? primaryColor,

在Flutter创建的Demo中,Theme是这样设置的。

代码语言:javascript
复制
return MaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(
    primarySwatch: Colors.blue,
  ),
  home: const MyHomePage(title: 'Flutter Demo Home Page'),
);

有没有人很好奇,primarySwatch和primaryColor,到底要设置哪个?到底谁才是真正的「主色调」?

首先,MaterialColor并不等于Color,它是基于MaterialDesign而产生的一套颜色体系。

在这个颜色系统中,基色和明暗不同的10种颜色作为一组处理,从而形成了MaterialColor。

前面代码中的Colors.blue,实际上就是一个MaterialColor,我们来看下它的实现。

代码语言:javascript
复制
static const MaterialColor blue = MaterialColor(
  _bluePrimaryValue,
  <int, Color>{
     50: Color(0xFFE3F2FD),
    100: Color(0xFFBBDEFB),
    200: Color(0xFF90CAF9),
    300: Color(0xFF64B5F6),
    400: Color(0xFF42A5F5),
    500: Color(_bluePrimaryValue),
    600: Color(0xFF1E88E5),
    700: Color(0xFF1976D2),
    800: Color(0xFF1565C0),
    900: Color(0xFF0D47A1),
  },
);
static const int _bluePrimaryValue = 0xFF2196F3;

由此可见,MaterialColor的10种颜色是怎么实现的。

事实上,MaterialColor的定义就是如此,一个基色,加上一个不同shade的Map。

如果你要自定义一个MaterialColor,那么这10种色调,也是必须要实现的。

?除了MaterialColor以外,还有一个MaterialAccentColor,它和MaterialColor类似,但是只有5种色调。 ?

Color

Colors:这个类是来自Material调色板的颜色。要在代码中访问它们,只需调用基色和shade值即可。

代码语言:javascript
复制
color: Colors.red
color: Colors.red[200]

Color:你可以将这个类用于Material调色板以外的颜色,因为它允许ARGB(Alpha, Red, Green, Blue)格式的颜色值。最常见的使用方法是像下面的代码这样传递十六进制颜色代码,其中0xFF代表完全不透明的颜色。

代码语言:javascript
复制
Color(0xFF42A5F5)

primarySwatch

接下来,我们继续来看前面提到的那个问题,为什么ThemeData中需要设置primarySwatch。

在theme_data的源代码中,我们可以发现这样的代码。

代码语言:javascript
复制
primarySwatch ??= Colors.blue;
primaryColor ??= isDark ? Colors.grey[900]! : primarySwatch;
final Brightness _primaryColorBrightness = estimateBrightnessForColor(primaryColor);
primaryColorLight ??= isDark ? Colors.grey[500]! : primarySwatch[100]!;
primaryColorDark ??= isDark ? Colors.black : primarySwatch[700]!;

从这里,我们就可以知道为什么在Demo中设不设置primarySwatch都会是蓝色的主题色的原因了。

那么一个具体的Flutter组件,是如何决定自己的主题的呢?以Appbar为例,我们在源代码中找到对应设置background的地方。

代码语言:javascript
复制
final Color backgroundColor = backwardsCompatibility
  ? widget.backgroundColor
    ?? appBarTheme.backgroundColor
    ?? theme.primaryColor
  : _resolveColor(
      states,
      widget.backgroundColor,
      appBarTheme.backgroundColor,
      colorScheme.brightness == Brightness.dark ? colorScheme.surface : colorScheme.primary,
    );

?不要被这里茫茫多的问号搞昏了,复习一下Dart语法吧。

  • 「?.」——代表非空访问,例如「myObject?.someProperty」,等价于——「(myObject != null) ? myObject.someProperty : null」
  • 「??」——代表避空判断,例如「a ?? 3」a为空时,返回3
  • 「??=」——同样是避空赋值,例如「a ??= 3」a为空时,a赋值为3

?

了解了这些之后,你应该就能看懂上面的代码了,原来Appbar的background是经过很多场景来判断的,简而言之:

  • 先判断是否在Appbar中设置了backgroundColor
  • 再判断是否指定了AppBarTheme.backgroundColor,也就是针对Appbar进行的Theme覆盖
  • 最后再根据是否黑夜模式来判断使用ColorScheme.primary还是ColorScheme.surface

大部分的Flutter组件,几乎都遵循这个判断流程,只是使用的Color类型不太一样。

但是,primaryColor并不是没用了,它可以用来更改组件的Theme,用于局部主题的使用。

代码语言:javascript
复制
Expanded(
    child: Theme(
        data: Theme.of(context).copyWith(primaryColor: Colors.red),
        child: Container(
          padding: const EdgeInsets.all(15.0),
          color: Theme.of(context).primaryColor,
          child: Text(
            'This Container overrides primaryColor',
            style: Theme.of(context).headline5,
          ),
        )))

ColorScheme

色彩的千变万化,最终会导致Theme属性的膨胀,这是可以预见的,所以你可以看看ThemeData有多少属性需要配置就知道了。

在ThemeData的构造函数中,有超过70种的Color和Theme,这要全部通过手工来配置,将是一个非常大的工作量。

因此,Flutter引入了ColorScheme属性,它是一组基于Material规范的25种颜色(9种必选色),可用于配置大多数组件的颜色属性。Flutter团队计划用定义好的ColorScheme来设计材质组件的样式。要使用colorScheme,你必须调用ThemeData.from()构造函数。

代码语言:javascript
复制
ThemeData.from(
  colorScheme: const ColorScheme.light().copyWith(
    primary: const Color(0xff455a64),
    primaryContainer: const Color(0xff1c313a),
    secondary: const Color(0xffffc400),
    secondaryContainer: const Color(0xffc79400),
  ),
);

创建ColorScheme只需要给对应的属性填上不同的色值即可。

代码语言:javascript
复制
ColorScheme colorScheme = ColorScheme(
  brightness: isDark ? Brightness.dark : Brightness.light,
  primary: accent1,
  onPrimary: Colors.white,
  secondary: accent1,
  onSecondary: Colors.white,
  error: Colors.red.shade400,
  onError: Colors.red.shade400,
  background: bg1,
  onBackground: textColor,
  surface: bg1,
  onSurface: textColor,
);

?新版本的Flutter,还提供了fromSeed方法,让开发者可以根据一个基色来生成符合Material Design规范的ColorScheme。 ?

MaterialDesign提供了ThemeBuilder来帮助开发者创建这些代码。

https://material-foundation.github.io/material-theme-builder/#/custom

下面这张图,就展示了Flutter中不同的Color之间的关系。

本文原创公众号:群英传,授权转载请联系微信,授权后,请在原创发表24小时后转载。

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-03-02,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 群英传 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MaterialColor
  • Color
  • primarySwatch
  • ColorScheme
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com