【问题标题】:Flutter Update State problem with setState()颤振更新状态问题与 setState()
【发布时间】:2021-10-21 16:09:13
【问题描述】:

我正在尝试从开关小部件更改主题。

但没有任何效果我没有错误,但没有预期的结果

.

在进行热重载时,它可以正常工作

当开关打开并进行热重载时,它会切换到深色主题

当开关关闭并进行热重载时,它会切换到浅色主题

这是要查看的代码

import 'package:flutter/material.dart';

mixin Th {
  static ThemeMode themeMode = ThemeMode.dark;
  static ThemeData themeData = ThemeData.dark();
  static bool isDark = false;
}

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  static String title = 'Hello Flutter';
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyHomePage(),
      title: MyApp.title,
      themeMode: Th.themeMode,
      darkTheme: Th.themeData,
    );
  }
}

class MyHomePage extends StatefulWidget {
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(MyApp.title),
        actions: [
          Switch(
            value: Th.isDark,
            onChanged: (newValue) {
              return setState(
                () {
                  if (!newValue) {
                    Th.themeMode = ThemeMode.light;
                    Th.themeData = ThemeData.light();
                    Th.isDark = newValue;
                    print('Is Dark = ${Th.isDark}');
                  } else if (newValue) {
                    Th.themeMode = ThemeMode.dark;
                    Th.themeData = ThemeData.dark();
                    Th.isDark = newValue;
                    print('Is Dark = ${Th.isDark}');
                  }
                },
              );
            },
          ),
        ],
      ),
    );
  }
}

在控制台中运行打印并获得预期结果

这里有什么问题?并感谢您的阅读。

在桌面“Windows 应用”的颤振和移动“Android 应用”的颤振上进行了测试

【问题讨论】:

标签: flutter


【解决方案1】:

The reason is that setState only changes the UI of that page only, 既然你已经在 Material 应用中定义了主题,你需要使用provider 包来对整个应用 UI 进行更改。

首先创建一个 dart 文件来通知听众有关主题的信息,并在其中放入以下代码:-

import 'package:flutter/material.dart';

class ThemeNotifier with ChangeNotifier {
  ThemeData _themeData;

  ThemeNotifier(this._themeData);

  getTheme() => _themeData; // to get current theme of the app

  setTheme(ThemeData themeData) async {
    _themeData = themeData;
    notifyListeners(); // to update the theme of the app
  }
}

在您的 pubspec.yaml 文件中添加 Shared prefs 插件

现在,让我们来处理 void main。因此,如果您在数据库中没有当前主题/模式的任何值,让我们创建一个函数来获取设备的当前主题。 例如,如果用户刚刚安装了应用程序,那么您不知道用户的主题选择,那么如果您提供基于用户移动主题的主题,那就太好了。

getSystemTheme()
  {
    var brightness = SchedulerBinding.instance.window.platformBrightness;
    bool darkModeOn = brightness == Brightness.dark;
    return darkModeOn;
  }

无论是否开启深色主题,上述函数都会返回布尔值

现在让我们从本地数据库中获取值并相应地提供主题。

SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values).then((_) {
    SharedPreferences.getInstance().then((prefs) {
      var darkModeOn = prefs.getBool('isDarkTheme') ?? getSystemTheme(); //if have value in database then that theme else the system theme will be used
      runApp(
        ChangeNotifierProvider<ThemeNotifier>(
          create: (_) => ThemeNotifier(darkModeOn ? MyThemes.darktheme : MyThemes.lightTheme),
          child: MyApp(),
        ),
      );
    });
  });

现在是 MyApp() 小部件的代码:-

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final themeNotifier = Provider.of<ThemeNotifier>(context);
    return Consumer<ThemeNotifier>(
      builder: (context, appState, child) {
        return MaterialApp(
          theme: themeNotifier.getTheme(),
          home: HomeScreen(),
        );
      },
    );
  }
}

如果您想为用户提供手动更改主题的选项,那么您可以为其创建一个开关并执行以下更新以动态更改主题(无需重新启动应用程序)。:-

    class Settings extends StatefulWidget {
    
      @override
      _SettingsState createState() => _SettingsState();
    }
    
    class _SettingsState extends State<Settings> {
      bool _darkTheme=false;

      void toggleSwitch(bool value, ThemeNotifier themeNotifier) async {
    (value)
        ? themeNotifier.setTheme(AppTheme.darktheme)
        : themeNotifier.setTheme(AppTheme.lighttheme);//here change of theme will take place
        var prefs = await SharedPreferences.getInstance();
        prefs.setBool('isDarkTheme', value); // and this code will save the boolean value whether darkmode is on or off to the local storage.
      }

      @override
      Widget build(BuildContext context) {
        final themeNotifier = Provider.of<ThemeNotifier>(context);
        _darkTheme = (themeNotifier.getTheme() == MyThemes.darktheme);

        return Scaffold(
            body: Row(
               mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Expanded(child: Text("Dark Mode",style: TextStyle(fontSize: 18),)),
                Switch(
                  value: _darkTheme,
                  onChanged: (val) {
                    setState(() {
                      _darkTheme = val;
                    });
                    toggleSwitch(val, themeNotifier);
                  },
                ),
              ],
            )
         );
      }
    }

P.S.:- 您可以删除共享首选项,但要存储用户选择的主题的值,这样每当他/她重新启动应用程序时,主题就会被维护,您应该添加它..

【讨论】:

    猜你喜欢
    • 2021-07-21
    • 1970-01-01
    • 1970-01-01
    • 2021-11-19
    • 2021-05-23
    • 2020-08-04
    • 2022-01-18
    • 2021-11-12
    • 2021-06-01
    相关资源
    最近更新 更多