我有一个MaterialApp小部件,可为应用程序内的所有小部件设置theme。我想在运行时从子Widget更改MaterialApptheme值,该子Widget没有直接引用其父MaterialApp

由于ThemeData是由InheritedWidget提供的,因此这似乎应该可行,但是我不知道如何更改theme的批发数量。有谁知道如何做到这一点?

这是拥有该应用程序其余部分的MaterialApp:

new MaterialApp(
    title: 'App Name',
    theme: initialTheme,
    routes: <String, WidgetBuilder>{
      '/' : ...,
    },
),

最佳答案

根据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;
  }

}

关于Flutter:如何在运行时更改MaterialApp主题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49164592/

10-16 05:21