I have created the following theme for my app:
ThemeData _buildDarkTheme() {
final baseTheme = ThemeData(fontFamily: "Sunflower",);
return baseTheme.copyWith(
brightness: Brightness.dark,
primaryColor: Colors.grey[800],
accentColor: Colors.grey[850]);
}
I then apply it to my app as follows:
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(...
However, when I try to access the accent color inside the container (or anywhere else) instead of it being the expected, Colors.grey[850], it instead defaults to blue. Also, trying to use the custom font Sunflower font family does not work, but when I instead use
new Text("Hello World", style: new TextStyle(fontFamily: "Sunflower"))
The font appears correctly.
I am new to flutter and dart so any help resolving these issues would be appreciated.
To share a Theme across an entire app, provide a ThemeData to the MaterialApp constructor. If no theme is provided, Flutter creates a default theme for you. MaterialApp( title: appName, theme: ThemeData( // Define the default brightness and colors. brightness: Brightness.
In Flutter, we can change the theme throughout the app with the help of ThemeData in MaterialApp constructor. The default theme will be shared throughout the app when no theme is provided. ); ThemeData is used to configure the appearance of the entire app.
This is to do with how context
and Theme.of
work.
From the Theme class source code:
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
(and Navigator.of(), ...
.of() etc), look at the context you pass them and then iterate upwards through the tree of widgets looking for a widget of the type specified.
Now, looking at your code
Widget build(BuildContext context) {
return new MaterialApp(
theme: _buildDarkTheme(),
home: new Scaffold(
appBar: _buildAppBar(),
body: new Container(
color: Theme.of(context).accentColor,
you can see that the context
you're passing into Theme.of
is actually the context above the theme you're creating. So it won't find your theme and will revert to the default. This is because the widget tree looks somewhat like the following (ignoring all the intermediate layers, with the arrow pointing to the context you're using.
MyApp - context <--------
MaterialApp
Theme
Scaffold
There are two ways to fix this; the first is to use a Builder
class to build your widget within a closure that has the context below the theme. That would look something like this:
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(...)
),
),
),
);
}
}
And it would make a tree that looks somewhat like this:
MyApp - context
MaterialApp
Theme
Scaffold
Builder - context <---------
The other (preferable) option is to split out the code for your builder into its own class - either a StatelessWidget
-inherited class or a StatefulWidget
and State
pair.
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