Flutter: Dynamic Themeing with Provider
Flutter provides (heh) us with an amazingly easy way to create mobile applications. Once again, a fundamental thing you have to master is the management of state
There are numerous patterns that can be used to manage state within Flutter, such as the BLoC pattern, Redux, setState
, MobX, Provider, and much more. Each method has a different way to manage the same concept. How do we pass data around our application in an efficient, truthful manner?
Installing Provider
Prior to answering this question with an example, we'll need to install the Provider
library into our project. Head over to your pubspec.yaml
and add the following to the dependencies
block:
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
provider: ^2.0.1
As always, it's important that you keep the tab spacing the same as the above.
Using ChangeNotifier
Now we'll need to create a class at lib/theme.dart
which uses with ChangeNotifier
as this gives us access to the notifyListeners
method. Inside of the class, we'll make a simple getTheme
and setTheme
method:
import 'package:flutter/material.dart';
class ThemeChanger with ChangeNotifier {
ThemeData _themeData;
ThemeChanger(this._themeData);
getTheme() => _themeData;
setTheme(ThemeData theme) {
_themeData = theme;
notifyListeners();
}
}
Once we're setting the new theme, we're calling notifyListeners
to push the changes to any client listeners. We'll see this in action next.
Interacting with ChangeNotifier
We can use the ChangeNotifierProvider
to give us the ability to listen to the value of our current Theme
. You can see this in the below example:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import './theme/theme.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ThemeChanger>(
builder: (_) => ThemeChanger(ThemeData.dark()),
child: new MaterialAppWithTheme(),
);
}
}
The key areas to consider is this part:
return ChangeNotifierProvider<ThemeChanger>(
builder: (_) => ThemeChanger(ThemeData.dark()),
child: new MaterialAppWithTheme(),
);
Using the builder
method, we can return a ThemeChanger
that uses the ThemeData.dark()
factory to generate a dark
theme by default. We can listen to this inside of our MaterialAppWithTheme
by using Provider.of()
:
class MaterialAppWithTheme extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Provider.of<ThemeChanger>(context);
return MaterialApp(
home: HomePage(),
theme: theme.getTheme(),
);
}
}
In order to see this, we'll need to create and import the HomePage
widget at pages/home.dart
:
import 'package:developer_school_mobile/theme/theme.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
ThemeChanger _themeChanger = Provider.of<ThemeChanger>(context);
return new Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Container(
child: Column(
children: <Widget>[
FlatButton(
child: Text('Dark Theme'),
onPressed: () => _themeChanger.setTheme(ThemeData.dark())),
FlatButton(
child: Text('Light Theme'),
onPressed: () => _themeChanger.setTheme(ThemeData.light())),
],
),
),
);
}
}
Whenever we click either of our buttons, it calls _themeChanger.setTheme(value)
which is Provided to our MaterialAppWithTheme
widget, and thus, our theme updates. In order to see this, you'll also need to ensure that home.dart
has been imported in main.dart
:
import './pages/home.dart';
This is how it looks:

developer.school Newsletter
Join the newsletter to receive the latest updates in your inbox.