flutter 用于Riverpod主题化的ChangeNotifierProvider

kgsdhlau  于 2022-11-30  发布在  Flutter
关注(0)|答案(2)|浏览(299)

我想根据切换按钮更改应用程序主题。我正在使用ChangeNotifier来做这件事。

class ThemesProvider extends ChangeNotifier {
  ThemeMode themeMode = ThemeMode.system;
  bool get isDarkMode => themeMode == ThemeMode.dark;
  void changeTheme(bool isOn) {
    themeMode = isOn ? ThemeMode.dark : ThemeMode.light;
    notifyListeners();
  }
}

这就是我用来更改主题的类。

final themesProvider = ChangeNotifierProvider((_) => ThemesProvider());

class MyApp extends ConsumerWidget {
  const MyApp({
    super.key,
  });
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final themeModeState = ref.watch(themesProvider).themeMode;
    return MaterialApp(
      theme: Themes.lightTheme,
      darkTheme: Themes.darkTheme,
      themeMode: themeModeState,
      debugShowCheckedModeBanner: false,
      home: const SignInScreen(),
    );
  }
}

那是我的主要文件。

final themesProvider = ChangeNotifierProvider((_) => ThemesProvider());

class MainScreen extends ConsumerWidget {
  const MainScreen({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final themeModeState = ref.watch(themesProvider);
    return Scaffold(
      appBar: AppBar(
        title: Text("Try Me"),
        leading: Consumer(
          builder: (context, ref, child) {
            return Switch(
                value: themeModeState.isDarkMode,
                onChanged: (value) {
                  themeModeState.changeTheme(value);
                });
          },
        ),
      ),
    );
  }
}

这就是我试图改变主题的地方。
第一个
看起来功能运行正常。我不知道哪里出错了。你们能帮我修一下吗?

dl5txlt9

dl5txlt91#

这个简短的范例如预期般运作:

void main() => runApp(const ProviderScope(child: MyApp()));

class ThemesProvider extends ChangeNotifier {
  ThemeMode themeMode = ThemeMode.system;
  bool get isDarkMode => themeMode == ThemeMode.dark;
  void changeTheme(bool isOn) {
    themeMode = isOn ? ThemeMode.dark : ThemeMode.light;
    notifyListeners();
  }
}

final themesProvider = ChangeNotifierProvider((_) => ThemesProvider());

class MyApp extends ConsumerWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final themeModeState = ref.watch(themesProvider).themeMode;

    return MaterialApp(
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      themeMode: themeModeState,
      debugShowCheckedModeBanner: false,
      home: const MainScreen(),
    );
  }
}

class MainScreen extends ConsumerWidget {
  const MainScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final themeModeState = ref.watch(themesProvider);
    return Scaffold(
      appBar: AppBar(
        title: Text("Try Me, current: ${themeModeState.themeMode}"),
        leading: Switch(
          value: themeModeState.isDarkMode,
          onChanged: (value) {
            themeModeState.changeTheme(value);
          },
        ),
      ),
    );
  }
}

问题大概就在这里:

...
theme: Themes.lightTheme,
darkTheme: Themes.darkTheme,
...

或者,您可能声明了ThemesProvider()的两个不同示例,这会产生一些影响(我认为不会)

syqv5f0l

syqv5f0l2#

对于ChangeNotifierStateNotifier,应调用通知程序上的函数。例如

ref.read(yourProvider.notifier).function()

因此,Switch小部件中的onChanged函数必须更改为以下内容:

onChanged: (value) {
  ref.read(themesProvider.notifier).changeTheme(value);
});

备注:在onPressed、onChanged等函数中应该使用read,而不是watch
通常不建议使用ChangeNotifier,而建议使用StateNotifier,这样可以提升不可变的架构,并使代码更易于维护。

相关问题