Чисто переопределяющие части темы локально в 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
, _themeData.textTheme
, затем _themeData.textTheme.subhead
).
Ответы
Ответ 1
Хотя я могу понять разочарование в необходимости "скопировать" все, так вы должны это сделать.
Данные неизменяемы в Flutter. Вы не можете их мутировать, вы вынуждены клонировать их с разными свойствами.
Поэтому ваше предположение верно: если вы хотите изменить вложенное свойство, вам также нужно клонировать всех его родителей. Что приводит к:
final ThemeData theme = Theme.of(context);
theme.copyWith(
textTheme: theme.textTheme.copyWith(
subhead: theme.textTheme.subhead.copyWith(
fontSize: 30.0,
),
),
);
Опять же: вы не можете этого избежать.
Ответ 2
Это поможет, если вы упакуете эту часть кода и сделаете его виджетом, чтобы ваше дерево было чище. Это как это сделано в этом примере.
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(),
...
)
)