在Flutter中完全覆盖主题的局部

时间:2018-09-15 13:20:52

标签: flutter

我有一个小部件,其中有两个TextField作为后代。我想对这些TextField应用相同的样式。我的理解是执行此操作的正确方法是将本地化主题应用于我的小部件树。以下是我的尝试。这是我的根窗口小部件的build函数的代码片段。没有更清洁的方法可以做到这一点吗?

final ThemeData _themeData = Theme.of(context);
return Theme( // HACK
  data: _themeData.copyWith(
    inputDecorationTheme: InputDecorationTheme(
      border: OutlineInputBorder(),
    ),
    textTheme: _themeData.textTheme.copyWith(
      subhead: _themeData.textTheme.subhead.copyWith(
        fontSize: 30.0,
      ),
    ),
  ),
  child: _buildTheRestOfMyWidgetTree(context),
);

让我烦恼的是,要覆盖单个属性(_themeData.textTheme.subhead.fontSize),我必须显式并手动制作三个中间数据结构(_themeData,然后是{{1})的副本},然后_themeData.textTheme)。

2 个答案:

答案 0 :(得分:2)

虽然我能理解必须“复制”所有内容的挫败感,但这是您应该这样做的方式。

数据在Flutter中是不可变的。您无法对其进行突变,而不得不使用不同的属性对其进行克隆。

因此,您的假设是正确的:如果要修改嵌套属性,则也必须克隆其所有父级。导致:

final ThemeData theme = Theme.of(context);
theme.copyWith(
  textTheme: theme.textTheme.copyWith(
    subhead: theme.textTheme.subhead.copyWith(
      fontSize: 30.0,
    ),
  ),
);

再次:您无法避免。

答案 1 :(得分:0)

如果将代码的那一部分打包并使其成为小部件,以使树更整洁,这将有所帮助。 example就是这样。

class TextFieldOverride extends StatelessWidget {
  const TextFieldOverride({this.child});
  final Widget child;
  @override
  Widget build(BuildContext context) {
    final themeData = Theme.of(context);
    return Theme(
      child: child,
      data: themeData.copyWith(
        inputDecorationTheme: InputDecorationTheme(
          border: OutlineInputBorder()),
      textTheme: themeData.textTheme.copyWith(
        subhead: themeData.textTheme.subhead.copyWith(
          fontSize: 30.0))));
  }
}

...

TextFieldOverride(
  child: TextField(...)
)

或者如果代码重复的地方很少,则可以直接进行更改:

...
child: TextField(
  style: Theme.of(context).textTheme.subhead.copyWith(fontSize: 30.0),
  decoration: InputDecoration(border: OutlineInputBorder(),
    ...
  )
)

或者最好的选择是创建一个为您完成上述任务的函数。

TextField buildTextField(BuildContext context) => TextField(
  style: Theme.of(context).textTheme.subhead.copyWith(fontSize: 30.0),
  decoration: InputDecoration(border: OutlineInputBorder(),
    ...
  )
)