【问题标题】:Unable to access the state of ValueNotifier inside the MaterialApp无法访问 MaterialApp 内 ValueNotifier 的状态
【发布时间】:2022-01-20 02:58:07
【问题描述】:

我一直在 Dart 和 Flutter 中尝试使用 ValueNotifier 并遇到了一个有趣的问题。 我定义了两个自定义主题并尝试使用 ValueListenableBuilder 从应用程序的两个不同部分访问它们 我能够在App 组件内的Container 中正确获取主题数据。但是,它不适用于MaterialApp。请说明为什么会这样。

PS:我知道有更好的方法来管理主题,我只是在尝试。

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final _themeManager = ThemeManager();
    return ValueListenableBuilder<ThemeData>(
        valueListenable: _themeManager.theme,
        builder: (context, theme, child) {
          return MaterialApp(
            title: 'Flutter Demo',
            // theme not updating ❌
            theme: theme,
            home: const App(),
          );
        });
  }
}

class Theme {
  static ThemeData primaryTheme =
      ThemeData(primarySwatch: Colors.amber, primaryColor: Colors.amber);
  static ThemeData secondaryTheme =
      ThemeData(primarySwatch: Colors.blue, primaryColor: Colors.blue);
}

class ThemeManager {
  final ValueNotifier<ThemeData> _theme =
      ValueNotifier<ThemeData>(Theme.primaryTheme);

  ValueNotifier<ThemeData> get theme => _theme;

  void changeTheme(ThemeData theme) {
    _theme.value = theme;
  }
}

class App extends StatelessWidget {
  const App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final _themeManager = ThemeManager();

    return Scaffold(
      appBar: AppBar(
        title: const Text('App'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ValueListenableBuilder<ThemeData>(
              valueListenable: _themeManager.theme,
              builder: (context, theme, child) {
                return Container(
                  height: 100,
                  width: 100,
                  // theme updating correctly ✔️
                  color: theme.primaryColor,
                );
              },
            ),
            const SizedBox(height: 20),
            ElevatedButton(
                onPressed: () {
                  _themeManager.theme.value =
                      _themeManager.theme.value == Theme.primaryTheme
                          ? Theme.secondaryTheme
                          : Theme.primaryTheme;
                },
                child: const Text('Toggle Theme')),
          ],
        ),
      ),
    );
  }
}

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    您正在使用ThemeManager 的两个不同实例。一个在MyApp 另一个在App Widget 的构建方法中。点击按钮时,您只更新了第二个实例,这就是为什么只更新容器的原因。尝试使用 ThemeManager 的单个实例或将 ThemeManager 定义为 Singleton。

    将 ThemeManager 更新为

    class ThemeManager {
      static ThemeManager? _instance;
    
      ThemeManager._();
    
      static ThemeManager get instance => _instance ??= ThemeManager._();
    
      final ValueNotifier<ThemeData> _theme =
          ValueNotifier<ThemeData>(Theme.primaryTheme);
    
      ValueNotifier<ThemeData> get theme => _theme;
    
      void changeTheme(ThemeData theme) {
        _theme.value = theme;
      }
    }
    

    并获取 ThemeManager 的实例为

        final _themeManager = ThemeManager.instance;
    

    这是dartpad上的更新代码。

    【讨论】:

    • 太棒了!这就是问题所在。谢谢
    猜你喜欢
    • 1970-01-01
    • 2019-03-24
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-09
    • 2016-06-20
    • 1970-01-01
    相关资源
    最近更新 更多