flutter 主题色彩管理组件 flex_color_scheme

前言

原文 https://ducafecat.com/blog/flutter-flex-color-scheme

平时我们做样式适配关心几个方面:

  • 设计稿颜色
  • 标记尺寸大小、比例
  • 全局修改为主
  • 快速可修改

今天将会介绍一个快速调整主题色彩样式的三方组件 flex_color_scheme

https://pub-web.flutter-io.cn/packages/flex_color_scheme

这个组件已经支持了 flutter 3.10 和 Material 3

参考

Flex color scheme

https://pub-web.flutter-io.cn/packages/flex_color_scheme

https://docs.flexcolorscheme.com/

https://rydmike.com/flexcolorscheme/themesplayground-v7-1/

Material 3

https://m3.material.io/

https://m3.material.io/theme-builder

https://space.bilibili.com/389903587/channel/collectiondetail?sid=246709

本机环境

❯ flutter --version
Flutter 3.10.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 796c8ef792 (2 天前) • 2023-06-13 15:51:02 -0700
Engine • revision 45f6e00911
Tools • Dart 3.0.5 • DevTools 2.23.1

步骤

第一步:配置依赖

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  ...

  flex_color_scheme: ^7.1.2

第二步:打开样式定制器

https://rydmike.com/flexcolorscheme/themesplayground-v7-1/

第三步:复制样式代码

lib/main.dart

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',

      // Theme config for FlexColorScheme version 7.1.x. Make sure you use
      // same or higher package version, but still same major version. If you
      // use a lower package version, some properties may not be supported.
      // In that case remove them after copying this theme to your app.
      theme: FlexThemeData.light(
        colors: const FlexSchemeColor(
          primary: Color(0xff065808),
          primaryContainer: Color(0xff9ee29f),
          secondary: Color(0xff365b37),
          secondaryContainer: Color(0xffaebdaf),
          tertiary: Color(0xff2c7e2e),
          tertiaryContainer: Color(0xffb8e6b9),
          appBarColor: Color(0xffb8e6b9),
          error: Color(0xffb00020),
        ),
        surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold,
        blendLevel: 7,
        appBarStyle: FlexAppBarStyle.material,
        appBarOpacity: 0.87,
        transparentStatusBar: false,
        appBarElevation: 12.5,
        subThemesData: const FlexSubThemesData(
          useTextTheme: true,
          useM2StyleDividerInM3: true,
          tabBarIndicatorWeight: 5,
          tabBarIndicatorTopRadius: 6,
        ),
        keyColors: const FlexKeyColors(
          useSecondary: true,
          useTertiary: true,
        ),
        visualDensity: FlexColorScheme.comfortablePlatformDensity,
        useMaterial3: true,
        swapLegacyOnMaterial3: true,
        // To use the Playground font, add GoogleFonts package and uncomment
        // fontFamily: GoogleFonts.notoSans().fontFamily,
      ),
      darkTheme: FlexThemeData.dark(
        colors: const FlexSchemeColor(
          primary: Color(0xff629f80),
          primaryContainer: Color(0xff274033),
          secondary: Color(0xff81b39a),
          secondaryContainer: Color(0xff4d6b5c),
          tertiary: Color(0xff88c5a6),
          tertiaryContainer: Color(0xff356c50),
          appBarColor: Color(0xff356c50),
          error: Color(0xffcf6679),
        ),
        surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold,
        blendLevel: 13,
        transparentStatusBar: false,
        subThemesData: const FlexSubThemesData(
          useTextTheme: true,
          useM2StyleDividerInM3: true,
          tabBarIndicatorWeight: 5,
          tabBarIndicatorTopRadius: 6,
        ),
        keyColors: const FlexKeyColors(
          useSecondary: true,
          useTertiary: true,
        ),
        visualDensity: FlexColorScheme.comfortablePlatformDensity,
        useMaterial3: true,
        swapLegacyOnMaterial3: true,
        // To use the Playground font, add GoogleFonts package and uncomment
        // fontFamily: GoogleFonts.notoSans().fontFamily,
      ),

      // If you do not have a themeMode switch, uncomment this line
      // to let the device system mode control the theme mode:
      themeMode: ThemeMode.system,

      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }

运行

通过 FlexSchemeColor 自定义颜色

const FlexSchemeData _myFlexScheme = FlexSchemeData(
  name: 'Midnight blue',
  description: 'Midnight blue theme, custom definition of all colors',
  light: FlexSchemeColor(
    primary: Color(0xFF00296B),
    primaryContainer: Color(0xFFA0C2ED),
    secondary: Color(0xFFD26900),
    secondaryContainer: Color(0xFFFFD270),
    tertiary: Color(0xFF5C5C95),
    tertiaryContainer: Color(0xFFC8DBF8),
  ),
  dark: FlexSchemeColor(
    primary: Color(0xFFB1CFF5),
    primaryContainer: Color(0xFF3873BA),
    secondary: Color(0xFFFFD270),
    secondaryContainer: Color(0xFFD26900),
    tertiary: Color(0xFFC9CBFC),
    tertiaryContainer: Color(0xFF535393),
  ),
);

FlexThemeData 是对 ThemeData 扩展

///
/// However, Dart does not yet support such extensions, see:

/// https://github.com/dart-lang/language/issues/723
extension FlexThemeData on ThemeData {
  /// Returns a [ThemeData] object defined by factory [FlexColorScheme.light]
  /// and its [FlexColorScheme.toTheme] method.
  static ThemeData light({
    /// The [FlexSchemeColor] that will be used to create the light
    /// [FlexColorScheme].
    ///
    /// You can use predefined [FlexSchemeColor] values from [FlexColor] or

    /// [FlexColor.schemes] map or define your own colors with
    /// [FlexSchemeColor] or [FlexSchemeColor.from].
    ///
    /// For using built-in color schemes, the convenience shortcut to select

    /// it with the [scheme] property is recommended and leaving [colors]
    /// undefined. If both are specified the scheme colors defined by [colors]
    /// are used. If both are null then [scheme] defaults to
    /// [FlexScheme.material], thus defining the resulting scheme.
    final FlexSchemeColor? colors,

FlexThemeData.light 返回的还是 ThemeData ,所以你可以加入自己的内容。

加入自定义样式定义

      // Theme config for FlexColorScheme version 7.1.x. Make sure you use
      // same or higher package version, but still same major version. If you
      // use a lower package version, some properties may not be supported.
      // In that case remove them after copying this theme to your app.
      theme: FlexThemeData.light(
        colors: const FlexSchemeColor(
          primary: Color(0xff065808),
          primaryContainer: Color(0xff9ee29f),
          secondary: Color(0xff365b37),
          secondaryContainer: Color(0xffaebdaf),
          tertiary: Color(0xff2c7e2e),
          tertiaryContainer: Color(0xffb8e6b9),
          appBarColor: Color(0xffb8e6b9),
          error: Color(0xffb00020),
        ),
        surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold,
        blendLevel: 7,
        appBarStyle: FlexAppBarStyle.material,
        appBarOpacity: 0.87,
        transparentStatusBar: false,
        appBarElevation: 12.5,
        subThemesData: const FlexSubThemesData(
          useTextTheme: true,
          useM2StyleDividerInM3: true,
          tabBarIndicatorWeight: 5,
          tabBarIndicatorTopRadius: 6,
        ),
        keyColors: const FlexKeyColors(
          useSecondary: true,
          useTertiary: true,
        ),
        visualDensity: FlexColorScheme.comfortablePlatformDensity,
        useMaterial3: true,
        swapLegacyOnMaterial3: true,
        // To use the Playground font, add GoogleFonts package and uncomment
        // fontFamily: GoogleFonts.notoSans().fontFamily,
      ).copyWith(
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: ElevatedButton.styleFrom(
            foregroundColor: Colors.white,
            backgroundColor: Colors.red,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(10),
            ),
            padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24),
          ),
        ),
      ),

通过 copyWith 的方式

FlexSubThemesData 子主题重写

    /// Activate using FlexColorScheme opinionated component sub-themes by
    /// passing in a default `FlexSubThemesData()`.
    ///
    /// To further configure the sub-themes, change the simple flat value

    /// properties as desired in `FlexSubThemesData()`.
    ///
    /// By default [FlexThemeData.light], [FlexThemeData.dark] and

    /// [FlexColorScheme.toTheme], do as little as they need to just
    /// provide a consistent Material 2 color schemed theme. The additions they
    /// do are described in [FlexColorScheme.toTheme].
    ///
    /// The original purpose of the opinionated sub-themes was to make it easy

    /// to add themed corner radius to all Widgets that support it, and to
    /// provide a consistent look on all buttons, including [ToggleButtons].
    ///
    /// Therefore the sub themes are a convenient way to opt-in on customized

    /// corner radius on Widgets using above themes. By opting in you can set
    /// corner radius for all covered Widgets to same corner radius in one go.
    /// There are also properties to override the global default for each widget
    /// to set different rounding per widget if so desired.
    ///
    /// By default, if a `defaultRadius` is not specified, each widgets corner

    /// radius and some other styling take inspiration from the Material 3 (M3)
    /// specification https://m3.material.io/ and uses its specifications as
    /// defaults when it is possible to do so in Flutter SDK theming when using
    /// Material2 mode and via defaults also in Material 3 mode.
    ///
    /// Starting from version 5, by opting in via a default [subThemesData] you

    /// get an extensive set of widget component sub themes applied.
    /// They can be customized via the [subThemesData] property, that has
    /// quick and flat sub theme configuration values in the data class
    /// [FlexSubThemesData].
    ///
    /// Customizable sub-themes are available for:

    ///
    /// * [AppBarTheme] for [AppBar] via [FlexSubThemes.appBarTheme].

    /// [BottomAppBarTheme] for [BottomAppBar] via
    ///   [FlexSubThemes.bottomAppBarTheme].
    /// [BottomNavigationBarThemeData] for [BottomNavigationBar] via
    ///   [FlexSubThemes.bottomNavigationBar].
    /// [BottomSheetThemeData] for [BottomSheet] via
    ///   [FlexSubThemes.bottomSheetTheme].
    /// [ButtonThemeData] for old deprecated buttons, via
    ///   [FlexSubThemes.buttonTheme].
    /// [CardTheme] for [Card] via [FlexSubThemes.cardTheme].
    /// [CheckboxThemeData] for [Checkbox] via [FlexSubThemes.checkboxTheme].
    /// [ChipThemeData] for [Chip] via [FlexSubThemes.chipTheme].
    /// [DatePickerThemeData] for [DatePicker] via
    ///   [FlexSubThemes.datePickerTheme].
    /// [DialogTheme] for [Dialog] via [FlexSubThemes.dialogTheme].
    /// [DrawerThemeData] for [Drawer] via [FlexSubThemes.drawerTheme].
    /// [DropdownMenuThemeData] for [DropDownMenu] via
    ///   [FlexSubThemes.dropdownMenuTheme].
    /// [ElevatedButtonThemeData] for [ElevatedButton] via
    ///   [FlexSubThemes.elevatedButtonTheme].
    /// [FilledButtonThemeData] for [FilledButton] via
    ///   [FlexSubThemes.filledButtonTheme].
    /// [FloatingActionButtonThemeData] for [FloatingActionButton] via
    ///   [FlexSubThemes.floatingActionButtonTheme].
    /// [IconButtonThemeData] for [IconButton] via
    ///   [FlexSubThemes.iconButtonTheme].
    /// [InputDecorationTheme] for [InputDecoration] via
    ///   [FlexSubThemes.inputDecorationTheme].
    /// [MenuBarThemeData] for [MenuBar] via [FlexSubThemes.menuBarTheme].
    /// [MenuButtonThemeData] for [MenuButton] via
    ///   [FlexSubThemes.menuButtonTheme].
    /// [MenuThemeData] for [MenuBar], [MenuAnchor] and [DropDownMenu] via
    ///   [FlexSubThemes.menuTheme].
    /// [ListTileThemeData] for [ListTile] via
    ///   [FlexSubThemes.listTileTheme].
    /// [NavigationBarThemeData] for [NavigationBar] via
    ///   [FlexSubThemes.navigationBarTheme].
    /// [NavigationDrawerThemeData] for [NavigationDrawer] via
    ///   [FlexSubThemes.navigationDrawerTheme].
    /// [NavigationRailThemeData] for [NavigationRail] via
    ///   [FlexSubThemes.navigationRailTheme].
    /// [OutlinedButtonThemeData] for [OutlinedButton] via
    ///   [FlexSubThemes.outlinedButtonTheme].
    /// [PopupMenuThemeData] for [PopupMenuButton] via
    ///   [FlexSubThemes.popupMenuTheme].
    /// [RadioThemeData] for [Radio] via [FlexSubThemes.radioTheme].
    /// [SliderThemeData] for [Slider] via [FlexSubThemes.sliderTheme].
    /// [SnackBarThemeData] for [SnackBar] via [FlexSubThemes.snackBarTheme].
    /// [SwitchThemeData] for [Switch] via [FlexSubThemes.switchTheme].
    /// [TabBarTheme] for [TabBar] via [FlexSubThemes.tabBarTheme].
    /// [TextButtonThemeData] for [TextButton] via
    ///   [FlexSubThemes.textButtonTheme].
    /// [TimePickerThemeData] for [TimePickerDialog] via
    ///   [FlexSubThemes.timePickerTheme].
    /// [ToggleButtonsThemeData] for [ToggleButtons] via
    ///   [FlexSubThemes.toggleButtonsTheme].
    /// [TooltipThemeData] for [Tooltip] via [FlexSubThemes.tooltipTheme].
    ///
    /// Defaults to null, resulting in FlexColorScheme not using any extra

    /// sub-theming in addition to those described in [FlexColorScheme.toTheme].
    final FlexSubThemesData? subThemesData,

subThemesData 中罗列了常见的样式属性

代码

https://github.com/ducafecat/flutter_develop_tips/tree/main/flutter_application_flex_color_scheme

小结

flex_color_scheme 是一个快速的样式设置工具,还修复了 flutter sdk 中的一些组件颜色不到位的缺陷,赶快用上吧。

感谢阅读本文

如果我有什么错?请在评论中让我知道。我很乐意改进。


© 猫哥 ducafecat.com

end

本文由 mdnice 多平台发布

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐