Flutter:如何在运行时更改主题亮度?

Flu*_*ery 6 material-design flutter

我有MaterialApp一个ThemeData初步设定到Brightness.light。我想Brightness.dark在运行时将亮度切换为,但是当我进行更改时,只有状态栏会发生变化 - Flutter 小部件实际上没有改变它们的亮度。

如何实现这种行为?

为了ThemeData在运行时更改,我创建了以下内容StatefulWidgetMaterialApp在主题更改时包装并重建它:

final ThemeData appTheme = ThemeData(
  brightness: Brightness.light,
);

class ThemeChanger extends StatefulWidget {
  static ThemeChangerState of (BuildContext context) {
    return context.ancestorStateOfType(TypeMatcher<ThemeChangerState>());
  }

  ThemeChanger({
    this.childBuilder,
  });

  final Widget Function(BuildContext, ThemeData) childBuilder;

  @override
  ThemeChangerState createState() => ThemeChangerState();
}

class ThemeChangerState extends State<ThemeChanger> {
  Brightness _brightness = Brightness.light;

  set brightness(Brightness brightness) {
    setState(() {
      _brightness = brightness;
    });
  }

  @override
  Widget build(BuildContext context) {
    return widget.childBuilder(
      context,
      appTheme.copyWith(
        brightness: _brightness
      ),
    );
  }
}

// Then in main.dart
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DemoTheme(
      childBuilder: (BuildContext context, ThemeData theme) {
        return MaterialApp(
          title: 'Materially Better',
          theme: theme,
          routes: {
            '/': (BuildContext context) {
              return LoginScreen();
            },
            'home': (BuildContext context) {
              return MainScreen();
            }
          },
          debugShowCheckedModeBanner: false,
        );
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Flu*_*ery 4

问题是,在构造函数中ThemeData使用它的brightness值来合成许多其他颜色,但这些颜色在ThemeData突变时不会重新计算。因此,解决方案是实例化一个全新的ThemeData而不是使用appTheme.copyWith(...).

改变这个:

appTheme.copyWith(
  brightness: _brightness,
),
Run Code Online (Sandbox Code Playgroud)

对此:

ThemeData(
  brightness: _brightness,
),
Run Code Online (Sandbox Code Playgroud)