扩展主题

此包可让您扩展Flutter中的**主题**,以便您可以定义和使用自己的属性。

它解决了什么问题?

假设您想为应用程序中的自定义小部件设置样式,但ThemeData中的属性并不完全符合您的需求。您宁愿添加自己的更具描述性的属性。
有几种方法可以做到这一点。

一种方法是为Theme创建扩展。但是,除非您开始在其中放置逻辑,否则它们不会如此动态。

另一种方法是创建您自己的Object,其中包含您的自定义样式,并像Theme一样通过InheritedWidget将它们提供给小部件树(或者您可以使用像provider这样的包)。

如果您只有一个样式,并且不支持浅色和深色主题,这就可以了。

但是,如果您确实想支持深色和浅色主题,并且您的应用程序有两个非常不同的部分应该使用自己的Theme,会发生什么?

您将得到

  • 主主题浅色
  • 主主题深色
  • 主自定义主题浅色(用于自定义样式)
  • 主自定义主题深色
  • 次主题浅色
  • 次主题深色
  • 次自定义主题浅色
  • 次自定义主题深色

这8个主题您需要跟踪,以便正确使用主题(主主题和次主题),以及这些主题的正确亮度(浅色/深色)变体。

您可能会得到16种不同的配置,而只有4种是有效的。

这正是扩展主题解决的问题。
它将采用默认的Theme,并将其与您的自定义属性合并到一个自定义主题中,这样您就不会混淆它们。

它是如何工作的?

扩展主题依赖于代码生成,根据您的自定义属性定义,创建一个全新的自定义主题,并提供所有必要的实用程序。

一个非常基础的定义示例

@ExtendedTheme()
abstract class _MyTheme {
    Color get myCustomColor;
}

现在您可以在终端中运行以下命令

flutter pub run build_runner build

这将生成以下内容

  1. 一个名为MyTheme的小部件(基于定义名称),您可以使用它,几乎与普通Theme小部件相同。事实上,这个小部件还将默认Theme添加到树中,因此每当您作用域MyTheme时,它都会使您的自定义属性和默认主题保持同步。
  2. 一个名为MyThemeData的类,它将包含您的自定义属性以及默认的ThemeData
  3. 一个名为$MyThemeInheritedWidget,它允许您在树中的任何位置获取MyThemeData

如何使用它?

既然您已经有了自定义主题,就可以开始使用了。

定义您的主题

您只需像以前使用ThemeData一样定义您的主题。

final myLightTheme = MyThemeData(
    themeData: ThemeData.light(),
    myCustomColor: Colors.orange,
);

final myDarkTheme = MyThemeData(
    themeData: ThemeData.dark(),
    myCustomColor: Colors.red,
);

将扩展主题添加到树中

为了能够访问您的自定义属性,我们必须将MyTheme添加到树中。

通常,您会将ThemeData设置为MaterialApptheme字段,这将其放在Navigator之上,并确保它在整个应用程序中可用。

我们不能只将MyThemeData放入theme字段,因为它不是ThemeData的子类。

要将MyTheme注入MaterialApp Navigator之上,我们可以使用builder字段。

您可以手动执行此操作

return MaterialApp(
    title: 'ExtendedTheme Demo',
    builder: (context, child) => MyTheme(
        light: myLightTheme,
        dark: myDarkTheme,
        child: child,
    ),
    home: const Content(),
);

如果您注入其他小部件,这可能会很有用,或者您可以使用生成的便捷构建器

return MaterialApp(
    title: 'ExtendedTheme Demo',
    builder: MyTheme.builder(
        light: myLightTheme,
        dark: myDarkTheme,
    ),
    home: const Content(),
);

如果您碰巧在应用程序中有多个独特的主题,如开头所述,您可以通过在需要它的地方将其添加到小部件树中,将MyTheme作用域限定到应用程序的特定部分。

return MyTheme(
    light: mySecondaryLightTheme,
    dark: mySecondaryDarkTheme,
    child: SecondaryThemedPage(),
),

使用您的自定义属性

访问自定义属性就像

return Container(
    color: MyTheme.of(context).myCustomColor,
);

ExtendedThemeData

在我们之前的例子中,我们只使用了一个简单的属性。
但是,如果我们想为自定义小部件添加样式怎么办?

就像ExtendedTheme一样,您可以定义ExtendedThemeData

假设我们有一个自定义小部件,它有几个属性

@ExtendedThemeData
abstract class _MyWidget {
    Color get backgroundColor;
    Color get foregroundColor;
    double? get width;
    double? get height;
    BoxShape get shape;
}

这将生成一个名为MyThemeData的类,它将包含我们定义的属性和一个适当的构造函数。

待办事项

  • 添加方便的copyWith、merge等方法
  • 添加默认值

GitHub

查看 Github