【问题标题】:Flutter: How do I change theme brightness at runtime?Flutter:如何在运行时更改主题亮度?
【发布时间】:2019-01-11 03:17:17
【问题描述】:

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

如何实现这种行为?

为了在运行时更改ThemeData,我创建了以下StatefulWidget,它包装了我的MaterialApp,并在主题更改时重新构建它:

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,
        );
      },
    );
  }
}

【问题讨论】:

    标签: flutter material-design


    【解决方案1】:

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

    改变这个:

    appTheme.copyWith(
      brightness: _brightness,
    ),
    

    到这里:

    ThemeData(
      brightness: _brightness,
    ),
    

    【讨论】:

    • 其实copyWith实例化了new类的实例。看方法代码就行了。
    【解决方案2】:

    我的解决方案如下:

    1. main.dart 中定义一个变量来表示亮度和一个改变状态的函数。

    2. 将函数传递给一个类,然后在需要的地方调用它。

    //main.dart
    class _MyAppState extends State<MyApp> {
      Brightness _brightness = Brightness.light;
    
      void _changeBrightness(Brightness newBrightness) {
        setState(() {
          _brightness = newBrightness;
        });
      }
    
      @override
      void initState() {
        super.initState();
        WidgetsBinding.instance.addPostFrameCallback((_) {
          //PASSING THE FUNCTION AS PARAMETER
          Util.changeBrightness = _changeBrightness;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Your app title',
          theme: ThemeData(
            primaryColor: const Color(0xFFb30047),
            brightness: _brightness,
            primarySwatch: Colors.blue,
            accentColor: Colors.white,
            /// ...and so on
    

    Util 类中

    class Util {
       static Brightness currentBrightness = Brightness.light;
       static Function changeBrightness;
       // ...further implementations
    

    然后在需要时调用它。就我而言,设置屏幕中的开关更改:

    darkModeChanged(bool newValue) {
       Preferences.setBool('darkMode', newValue);
       setState(() {
         _darkMode = newValue;
         Util.currentBrightness = _darkMode ? Brightness.dark : Brightness.light;        
         Util.changeBrightness(Util.currentBrightness);
       });
    }
    

    【讨论】:

      【解决方案3】:

      您可以查看以下库:https://github.com/Norbert515/dynamic_theme

      它允许您在运行时动态更改应用的整个主题数据或亮度。

      【讨论】:

        【解决方案4】:

        您可以在运行时使用 ThemeBuilder 更改主题:

        setState(() {
          ThemeBuilder.of(context).changeTheme();
        });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-11-02
          • 2022-11-11
          • 1970-01-01
          • 2020-04-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-06-30
          相关资源
          最近更新 更多