如何在 Flutter 中的小部件下设置所有 Text 小部件的颜色?

Posted

技术标签:

【中文标题】如何在 Flutter 中的小部件下设置所有 Text 小部件的颜色?【英文标题】:How to set color of all Text widgets under a widget in Flutter? 【发布时间】:2021-08-14 07:50:51 【问题描述】:

根据this answer,我所要做的就是用Theme 包装一个小部件并提供ThemeData。我从build 方法返回一个小部件,如下所示:

    Theme( // wrapping `Card` widget with a theme
      data: Theme.of(context).copyWith( // extend main theme
        textTheme: Theme.of(context).textTheme.copyWith( // extend main text theme
              subtitle1: TextStyle(
                color: Colors.white, // subtitle text color to white
              ),
              caption: TextStyle(
                color: Colors.white, // caption text color to white
              ),
            ),
      ),
      child: Card( // card widget as a child of theme
        // ... other stuff ...
        child: Container(
            margin: _margin,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Text(
                  profile.alias,
                  style: Theme.of(context).textTheme.subtitle1, // set text style to subtitle1
                ),
                Expanded(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.end,
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: [
                      Text(
                        'Joined $timeago.format(profile.dateJoined)',
                        style: Theme.of(context).textTheme.caption, // set text style to subtitle2
                        textAlign: TextAlign.right,
                      ),
                      Text(
                        'Has $profile.stats.subscriberCount == null ? 0 : profile.stats.subscriberCount subscribers',
                        style: Theme.of(context).textTheme.caption, // set text style to caption
                        textAlign: TextAlign.right,
                      ),
                      Text(
                        'Following $profile.stats.followingCount == null ? 0 : profile.stats.followingCount people',
                        style: Theme.of(context).textTheme.caption, // set text style to caption
                        textAlign: TextAlign.right,
                      ),
                    ],
                  ),
                ),
              ],
            )),
      ),
    );

奇怪的是,这不会影响我的文字。它仍然保持黑色。

可能有一些我不理解的主题。有没有办法将主题(在本例中为文本颜色)部分应用到影响所有直接和间接子级的小部件?


环境

颤振 2.0.6 飞镖 2.12.3

【问题讨论】:

你在项目中定义主题的地方也定义了文本的颜色,所以当你调用主题数据时,它会反映在你的卡片上试试这个 使用Theme() 你已经改变了Themechild 不要再次使用style: Theme.of(context).textTheme.subtitle1Text() 小部件使用bodyText2 主题所以而不是使用textTheme.subtitle1 更改它到textTheme.bodyText2 试试这样。添加这样的属性style: Theme.of(context).textTheme.subtitle1 你再次设置MaterialApp() 的属性而不是Theme() 【参考方案1】:

这里是一个示例,说明如何使用Theme() 对特定小部件使用全局主题和本地主题。

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // Global Theme
        primarySwatch: Colors.blue,
        textTheme: Theme.of(context).textTheme.copyWith(
              bodyText2: TextStyle(
                color: Colors.orangeAccent,
                fontWeight: FontWeight.bold,
              ),
            ),
        cardTheme: CardTheme(
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.all(Radius.circular(20)),
            ),
            color: Colors.blueGrey),
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text("List Builder"),
        ),
        body: HomePage(),
      ),
    );
  


class HomePage extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Column(
      children: [
        Center(child: Text("Using MaterialApp theme")),
        Expanded(
          child: ListView.builder(
            itemCount: 4,
            itemBuilder: (context, index) 
              return Theme(
                // Child Theme
                data: Theme.of(context).copyWith(
                  textTheme: TextTheme(
                    bodyText2: TextStyle(color: Colors.greenAccent),
                  ),
                  cardTheme: CardTheme(
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.all(Radius.circular(20)),
                    ),
                    color: Colors.red,
                  ),
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Card(
                      // Card Theme of Theme() data
                      child: Container(
                        width: MediaQuery.of(context).size.width * 0.4,
                        height: MediaQuery.of(context).size.height * 0.1,
                        child: Center(
                          child: Text(
                            "Hello (Using Theme())",
                          ),
                        ),
                      ),
                    ),
                    Container(
                      width: MediaQuery.of(context).size.width * 0.4,
                      height: MediaQuery.of(context).size.height * 0.1,
                      child: Card(
                        // Card Theme of MaterialApp
                        child: Center(
                          child: FittedBox(
                            child: Text(
                              "Welcome(card theme from MaterialApp)",
                              style: Theme.of(context).textTheme.bodyText2,
                            ),
                          ),
                        ),
                        shape: Theme.of(context).cardTheme.shape,
                        color: Theme.of(context).cardTheme.color,
                      ),
                    ),
                  ],
                ),
              );
            ,
          ),
        ),
      ],
    );
  

这是输出

【讨论】:

因此,不使用子 style 属性的子 Text 小部件将使用子主题。这是相当反直觉的。如果我想拥有这种 基本的标题样式 并将其扩展到子级怎么办?就在我这么想的时候,一件事打在了我的脑海里。如果我只是用Builder 小部件包装Text 小部件以提供一个新的BuildContext,它属于子级,从而提供子主题。它确实有效。 是的,它也可以这样工作。如果它有效,我还能说什么。【参考方案2】:

TL;DR:如果您想将主题应用于所有子级,请将Builder 用作Theme 的子级。


所以,我上面的代码似乎使用了 build 方法的上下文,它是父级的。它改变了Theme直接子代 的主题。这很违反直觉,但幸运的是,有一种方法可以使用 Builder 小部件初始化全新的 BuildContext

因此,如果您想将主题应用到所有孩子无论他们是直接孩子还是非直接孩子,请始终使用Builder 作为Theme 的直接孩子。

Theme(
  data: // your theme data here
  child: Builder(
    builder: (context) => // this is where you do stuff
  )
)

注意Builder 如何提供一个名为contextBuildContext?这是一个全新的上下文,实际上包含我们刚刚创建的subtheme,而不是build 方法提供的context。因此,当您在某处的Builder 小部件下创建Text 小部件时:

// under Builder widget somewhere
Text(
  'my text',
  style: Theme.of(context).textTheme.caption // we have a context here
)

这里的context 使用了Builder 小部件提供的上下文,而不是build 方法,这使它直观。

另外,我使用Theme.of 的原因是因为我想扩展主主题,而不是创建一个空主题。而且Flutter有很多预定义的文本样式,如bodyText1bodyText2heading1(最多6个)、caption等,我可以用这个方法。

这至少是我解决问题的方法,并且代码是有意义的。

【讨论】:

以上是关于如何在 Flutter 中的小部件下设置所有 Text 小部件的颜色?的主要内容,如果未能解决你的问题,请参考以下文章

如何在无效输入时摇动 Flutter 中的小部件?

如何在 Flutter 中移动屏幕中的小部件

如何从 Flutter-web 中的小部件创建图像?

如何在 Flutter 的 ListView 中显示特定小部件的子小部件?

Flutter:如何将图像(裁剪)放入下一个有状态/更少的小部件

如何将值从initstate传递给flutter中的小部件