我有一个MaterialAppWidget,theme可以为应用程序中的所有小部件设置.我想在运行时从没有任何直接引用其父级的子窗口小部件更改MaterialApps theme值MaterialApp.
看来这应该是可能的,因为它ThemeData是由一个提供的InheritedWidget,但我无法弄清楚如何改变theme批发.有谁知道如何做到这一点?
这是MaterialApp拥有应用程序其余部分的:
new MaterialApp(
title: 'App Name',
theme: initialTheme,
routes: <String, WidgetBuilder>{
'/' : ...,
},
),
Run Code Online (Sandbox Code Playgroud)
根据Dan Field的建议,我得出了以下解决方案.如果有人有改进,请随意加入:
// How to use: Any Widget in the app can access the ThemeChanger
// because it is an InheritedWidget. Then the Widget can call
// themeChanger.theme = [blah] to change the theme. The ThemeChanger
// then accesses AppThemeState by using the _themeGlobalKey, and
// the ThemeChanger switches out the old ThemeData for the new
// ThemeData in the AppThemeState (which causes a re-render).
final _themeGlobalKey = new GlobalKey(debugLabel: 'app_theme');
class AppTheme extends StatefulWidget {
final child;
AppTheme({
this.child,
}) : super(key: _themeGlobalKey);
@override
AppThemeState createState() => new AppThemeState();
}
class AppThemeState extends State<AppTheme> {
ThemeData _theme = DEV_THEME;
set theme(newTheme) {
if (newTheme != _theme) {
setState(() => _theme = newTheme);
}
}
@override
Widget build(BuildContext context) {
return new ThemeChanger(
appThemeKey: _themeGlobalKey,
child: new Theme(
data: _theme,
child: widget.child,
),
);
}
}
class ThemeChanger extends InheritedWidget {
static ThemeChanger of(BuildContext context) {
return context.inheritFromWidgetOfExactType(ThemeChanger);
}
final ThemeData theme;
final GlobalKey _appThemeKey;
ThemeChanger({
appThemeKey,
this.theme,
child
}) : _appThemeKey = appThemeKey, super(child: child);
set appTheme(AppThemeOption theme) {
switch (theme) {
case AppThemeOption.experimental:
(_appThemeKey.currentState as AppThemeState)?.theme = EXPERIMENT_THEME;
break;
case AppThemeOption.dev:
(_appThemeKey.currentState as AppThemeState)?.theme = DEV_THEME;
break;
}
}
@override
bool updateShouldNotify(ThemeChanger oldWidget) {
return oldWidget.theme == theme;
}
}
Run Code Online (Sandbox Code Playgroud)
这是此处回答的问题的一个具体案例:Force Flutter to redraw all widgets
看看那个问题中提到的股票样本,特别注意:https : //github.com/flutter/flutter/blob/master/examples/stocks/lib/main.dart https://github.com/颤振/颤振/blob/master/examples/stocks/lib/stock_settings.dart
请注意以下事项:
_configuration,由 更新configurationUpdaterconfigurationUpdater 传递给需要它的应用程序的孩子您也可以使用StreamController.
只需复制并粘贴此代码。这是一个工作样本。你不需要任何图书馆,它超级简单
import 'dart:async';
import 'package:flutter/material.dart';
StreamController<bool> isLightTheme = StreamController();
main() {
runApp(MainApp());
}
class MainApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder<bool>(
initialData: true,
stream: isLightTheme.stream,
builder: (context, snapshot) {
return MaterialApp(
theme: snapshot.data ? ThemeData.light() : ThemeData.dark(),
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(title: Text("Dynamic Theme")),
body: SettingPage()));
});
}
}
class SettingPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <
Widget>[
RaisedButton(
color: Colors.blue,
child: Text("Light Theme", style: TextStyle(color: Colors.white)),
onPressed: () {
isLightTheme.add(true);
}),
RaisedButton(
color: Colors.black,
child: Text("Dark Theme", style: TextStyle(color: Colors.white)),
onPressed: () {
isLightTheme.add(false);
}),
])));
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5892 次 |
| 最近记录: |