I have a widget which has two TextField
s as descendants. I would like to apply the same styling to these TextField
s. My understanding is that the right way to do this is to apply a localized theme to my widget tree. The following is my attempt. This is a code snippet from my root widget's build
function. Is there not a cleaner way to do this?
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),
);
The thing that I am annoyed by is that to override a single property (_themeData.textTheme.subhead.fontSize
), I have to explicitly and manually make copies of three intermediate data structures (_themeData
, then _themeData.textTheme
, then _themeData.textTheme.subhead
).
Using copywith to override the theme data in flutter app developing. Sample code of flutter theme data with copywith properties. // This widget is the root of your application.
ThemeData class Null safety. Defines the configuration of the overall visual Theme for a MaterialApp or a widget subtree within the app. The MaterialApp theme property can be used to configure the appearance of the entire app.
While I can understand the frustration of having to "copy" everything, this is how you should do it.
Data are immutable in Flutter. You cannot mutate them, you are forced to clone them with different properties.
Therefore your assumption is correct: If you want to modify a nested property, you have to clone all of its parents too. Which leads to:
final ThemeData theme = Theme.of(context);
theme.copyWith(
textTheme: theme.textTheme.copyWith(
subhead: theme.textTheme.subhead.copyWith(
fontSize: 30.0,
),
),
);
Again: you cannot avoid it.
It would help if you packaged that part of the code up and made it a widget so that your tree is cleaner. That's how it's done in this 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(...)
)
Or if there are few places the code will be duplicated, you can just make the changes directly:
...
child: TextField(
style: Theme.of(context).textTheme.subhead.copyWith(fontSize: 30.0),
decoration: InputDecoration(border: OutlineInputBorder(),
...
)
)
Or perhaps the best choice is to create a function that does the above for you.
TextField buildTextField(BuildContext context) => TextField(
style: Theme.of(context).textTheme.subhead.copyWith(fontSize: 30.0),
decoration: InputDecoration(border: OutlineInputBorder(),
...
)
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With