【问题标题】:Custom theme not working properly. [Flutter]自定义主题无法正常工作。 [扑]
【发布时间】:2018-06-18 20:56:54
【问题描述】:

我为我的应用创建了以下主题:

ThemeData _buildDarkTheme() {
  final baseTheme = ThemeData(fontFamily: "Sunflower",);
  return baseTheme.copyWith(
      brightness: Brightness.dark,
      primaryColor: Colors.grey[800],
      accentColor: Colors.grey[850]);
}

然后我将它应用到我的应用程序中,如下所示:

class MyApp extends StatelessWidget {
  MyApp({Key key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        theme: _buildDarkTheme(),
        home: new Scaffold(
          appBar: _buildAppBar(),
          body: new Container(
            color: Theme.of(context).accentColor,
            height: double.infinity,
            child: new ListView.builder(...

但是,当我尝试访问容器内(或其他任何地方)的强调色而不是预期的 Colors.grey[850] 时,它默认为蓝色。另外,尝试使用自定义字体 Sunflower 字体系列不起作用,但是当我改为使用时

new Text("Hello World", style: new TextStyle(fontFamily: "Sunflower"))

字体显示正确。

我是 flutter 和 dart 的新手,所以如果能帮助解决这些问题,我们将不胜感激。

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    这与contextTheme.of 的工作方式有关。

    来自Theme类源码:

      static ThemeData of(BuildContext context, { bool shadowThemeOnly = false }) {
        final _InheritedTheme inheritedTheme =
            context.inheritFromWidgetOfExactType(_InheritedTheme);
        if (shadowThemeOnly) {
          if (inheritedTheme == null || inheritedTheme.theme.isMaterialAppTheme)
            return null;
          return inheritedTheme.theme.data;
        }
    
        final ThemeData colorTheme = (inheritedTheme != null) ? inheritedTheme.theme.data : _kFallbackTheme;
        final MaterialLocalizations localizations = MaterialLocalizations.of(context);
        final TextTheme geometryTheme = localizations?.localTextGeometry ?? MaterialTextGeometry.englishLike;
        return ThemeData.localize(colorTheme, geometryTheme);
      }
    

    Theme.of(和 Navigator.of()、....of() 等),查看传递给它们的上下文,然后向上遍历小部件树,寻找指定类型的小部件。

    现在,看看你的代码

    Widget build(BuildContext context) {
        return new MaterialApp(
            theme: _buildDarkTheme(),
            home: new Scaffold(
              appBar: _buildAppBar(),
              body: new Container(
                color: Theme.of(context).accentColor,
    

    您可以看到您传递给Theme.ofcontext 实际上是您正在创建的主题之上的上下文。所以它不会找到您的主题,并将恢复为默认值。这是因为小部件树看起来有点像以下(忽略所有中间层,箭头指向您正在使用的上下文。

    MyApp - context <--------
      MaterialApp
        Theme
          Scaffold
            
    

    有两种方法可以解决此问题;第一种是使用Builder 类在具有主题下方上下文的闭包中构建小部件。看起来像这样:

    class MyApp extends StatelessWidget {
      MyApp({Key? key}) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: _buildDarkTheme(),
          home: Scaffold(
            appBar: _buildAppBar(),
            body: Builder(
              builder: (context) => Container(
                color: Theme.of(context).accentColor,
                height: double.infinity,
                child: ListView.builder(...)
              ),
            ),
          ),
        );
      }
    }
    

    它会生成一棵看起来像这样的树:

    MyApp - context
      MaterialApp
        Theme
          Scaffold
            Builder - context <---------
    

    另一个(首选)选项是将构建器的代码拆分为自己的类 - StatelessWidget-inherited 类或 StatefulWidgetState 对。

    【讨论】:

    • 感谢它的精彩教程,你能帮我添加字体家族吗
    • 谢谢,这解决了我的问题,脚手架正在拾取更高级别的上下文。
    • Builder 正是我想要的。
    • MaterialApp 发生了重大变化。它正在更新 ThemeData 的使用情况。如果这个答案不是你的解决方案。检查:flutter.dev/docs/release/breaking-changes/…
    【解决方案2】:

    我在 MaterialApp 类中使用主题时遇到了同样的问题。如果您希望整个 Flutter 应用程序只有一个主题,您只需在主页中使用一个主题(调用所有其他页面的主题)。

    这样做后,在其他页面中,永远不要返回 MaterialApp 类,否则它将覆盖您的主题并使用默认主题。

    这是我主页的代码:

                Widget build(BuildContext context) {
    
                return MaterialApp(
                theme: ThemeData(
                fontFamily: "Test",
                primaryColor: Colors.yellow,
                buttonColor: Colors.yellow,
                 ),
                 routes: {
    
                 '/': (BuildContext context) => AuthPage(),
                    },
                 );
    

    之后,在 AuthPage 中,返回 Scaffold 而不是 MaterialApp。

    【讨论】:

    • 这个答案应该是公认的答案。谢谢@Riad
    【解决方案3】:

    为什么不创建一个像这样的_darkTheme 变量:

    ThemeData _darkTheme = _buildDarkTheme();
    

    然后用它来定义颜色?

    class MyApp extends StatelessWidget {
      MyApp({Key key}) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            theme: _buildDarkTheme(),
            home: Scaffold(
              appBar: _buildAppBar(),
              body: Container(
                color: _darkTheme.accentColor,
                height: double.infinity,
                child: ListView.builder(...
    

    【讨论】:

    • 对于这个狭窄的用例可能是最好的。但是全球可用主题的目的是您可以在任何地方使用它。 Theme.of() 解决方案适用于主题声明下的任何上下文。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-07
    相关资源
    最近更新 更多