我希望用户可以更改主题颜色并将其保存在我的应用中。但是,我不知道在应用程序开始运行时如何加载已保存的主题颜色。例如,我想直接在下面的注释位置加载保存的主题颜色。我尝试了SharedPreference。但是,SharedPreference实例需要与 await 一起运行。似乎无法在这里使用。有什么方法可以直接在这里加载保存的主题,而不是使用setState之类的东西?
import 'package:flutter/material.dart'; void main() => runApp(new MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter Demo', theme: // how to load saved theme here? ), home: new MyHomePage(title: 'Flutter Demo Home Page'), ); } }
这个答案更进一步。它显示了如何加载和保存主题首选项,如何构建ThemeData和如何从应用程序页面更改主题。
ThemeData
shared_preferences
InheritedWidget
控制器的外观如下:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// provides the currently selected theme, saves changed theme preferences to disk class ThemeController extends ChangeNotifier { static const themePrefKey = 'theme'; ThemeController(this._prefs) { // load theme from preferences on initialization _currentTheme = _prefs.getString(themePrefKey) ?? 'light'; } final SharedPreferences _prefs; String _currentTheme; /// get the current theme String get currentTheme => _currentTheme; void setTheme(String theme) { _currentTheme = theme; // notify the app that the theme was changed notifyListeners(); // store updated theme on disk _prefs.setString(themePrefKey, theme); } /// get the controller from any page of your app static ThemeController of(BuildContext context) { final provider = context.inheritFromWidgetOfExactType(ThemeControllerProvider) as ThemeControllerProvider; return provider.controller; } } /// provides the theme controller to any page of your app class ThemeControllerProvider extends InheritedWidget { const ThemeControllerProvider({Key key, this.controller, Widget child}) : super(key: key, child: child); final ThemeController controller; @override bool updateShouldNotify(ThemeControllerProvider old) => controller != old.controller; }
这是您将控制器和InheritedWidget应用程序使用的方式:
void main() async { // load the shared preferences from disk before the app is started final prefs = await SharedPreferences.getInstance(); // create new theme controller, which will get the currently selected from shared preferences final themeController = ThemeController(prefs); runApp(MyApp(themeController: themeController)); } class MyApp extends StatelessWidget { final ThemeController themeController; const MyApp({Key key, this.themeController}) : super(key: key); @override Widget build(BuildContext context) { // use AnimatedBuilder to listen to theme changes (listen to ChangeNotifier) // the app will be rebuilt when the theme changes return AnimatedBuilder( animation: themeController, builder: (context, _) { // wrap app in inherited widget to provide the ThemeController to all pages return ThemeControllerProvider( controller: themeController, child: MaterialApp( title: 'Flutter Demo', theme: _buildCurrentTheme(), home: MyHomePage(), ), ); }, ); } // build the flutter theme from the saved theme string ThemeData _buildCurrentTheme() { switch (themeController.currentTheme) { case "dark": return ThemeData( brightness: Brightness.dark, primarySwatch: Colors.orange, ); case "light": default: return ThemeData( brightness: Brightness.light, primarySwatch: Colors.blue, ); } } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: new AppBar(), body: Center( child: Column( children: <Widget>[ RaisedButton( onPressed: () { // thanks to the inherited widget, we can access the theme controller from any page ThemeController.of(context).setTheme('light'); }, child: Text('Light Theme'), ), RaisedButton( onPressed: () { ThemeController.of(context).setTheme('dark'); }, child: Text('Dark Theme'), ) ], ), ), ); } }