In this example app, both language and theme can be set, and both are implemented using ChangeNotifierProvider: we use Consumer2 in the main function to depend on ThemeModel and LocaleModel. Therefore, when we change the current settings in the language and theme settings pages, the builder for Consumer2 will be re-executed, building a new MaterialApp, so the modifications will take effect immediately. Let’s look at the implementation of the language and theme settings pages.
1 Language Selection Page
The app's language selection page provides three options: Simplified Chinese, American English, and Follow System. We highlight the currently used language in the app and add a checkmark icon next to it, implemented as follows:
import '../index.dart';
class LanguageRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
var color = Theme.of(context).primaryColor;
var localeModel = Provider.of<LocaleModel>(context);
var gm = GmLocalizations.of(context);
Widget _buildLanguageItem(String lan, value) {
return ListTile(
title: Text(
lan,
// Highlight the app's current language
style: TextStyle(color: localeModel.locale == value ? color : null),
),
trailing: localeModel.locale == value ? Icon(Icons.done, color: color) : null,
onTap: () {
// This line of code will notify MaterialApp to rebuild
localeModel.locale = value;
},
);
}
return Scaffold(
appBar: AppBar(
title: Text(gm.language),
),
body: ListView(
children: <Widget>[
_buildLanguageItem("中文简体", "zh_CN"),
_buildLanguageItem("English", "en_US"),
_buildLanguageItem(gm.auto, null),
],
),
);
}
}The logic of the above code is quite simple. The only thing to note is that we defined the _buildLanguageItem(...) method inside the build(...) method. This allows the method to share variables from the context of build(...), in this case, sharing localeModel. However, if the implementation of _buildLanguageItem(...) were more complex, it would be better to define it as a method of the LanguageRoute class. The running effect of this page is shown in Figures :

The language switch takes effect immediately.
2 Theme Selection Page
A complete theme includes many options defined in ThemeData. For simplicity, we only configure the theme color in this example. We provide several predefined theme colors for users to choose from, and clicking on a color block updates the theme. The implementation code for the theme selection page is as follows:
class ThemeChangeRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(GmLocalizations.of(context).theme),
),
body: ListView( // Display theme color blocks
children: Global.themes.map<Widget>((e) {
return GestureDetector(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 16),
child: Container(
color: e,
height: 40,
),
),
onTap: () {
// After the theme update, MaterialApp will rebuild
Provider.of<ThemeModel>(context, listen: false).theme = e;
},
);
}).toList(),
),
);
}
}The running effect is shown in Figure :

After clicking on another theme color block, the app's theme color switches and takes effect immediately.