使用Riverpod与SharedPreferences时Flutter Switch过渡卡顿问题
我在应用中有一个简单的Switch组件,希望更新其状态并保存到SharedPreferences中,目前使用Riverpod来读取SharedPreferences数据。发现仅用setState()不结合SharedPreferences时,Switch的切换过渡十分流畅,但通过Provider获取值时,点击Switch后过渡瞬间完成毫无动画,推测是状态处理方式有误。
有问题的代码(Riverpod + SharedPreferences)
class SwitchExample extends ConsumerStatefulWidget { const SwitchExample({super.key}); @override ConsumerState<SwitchExample> createState() => _SwitchExampleState(); } class _SwitchExampleState extends ConsumerState<SwitchExample> { @override Widget build(BuildContext context) { final settings = ref.watch(settingsProvider); return Switch( value: settings.isDynamicColorEnabled, activeColor: Colors.red, onChanged: (bool value) async { await ref.read(settingsProvider.notifier).setDynamicColorEnabled(value); }, ); } }
正常的 setState 代码
class SwitchExample extends StatefulWidget { const SwitchExample({super.key}); @override State<SwitchExample> createState() => _SwitchExampleState(); } class _SwitchExampleState extends State<SwitchExample> { bool light = true; @override Widget build(BuildContext context) { return Switch( value: light, activeColor: Colors.red, onChanged: (bool value) { setState(() { light = value; }); }, ); } }
问题原因
Switch组件的过渡动画依赖即时的状态变更反馈:用setState时,点击后立刻更新本地状态并触发UI重建,动画自然流畅;但通过Provider异步更新时,SharedPreferences的写入是耗时操作,Provider状态更新延迟,导致Switch等待状态同步完成才刷新,跳过了过渡动画。
解决方案:本地状态优先更新,异步同步持久化
先通过setState更新组件本地状态,让Switch立刻播放动画,再在后台异步完成SharedPreferences和Provider的状态同步,兼顾动画流畅性和状态持久化。
修改后的代码:
class SwitchExample extends ConsumerStatefulWidget { const SwitchExample({super.key}); @override ConsumerState<SwitchExample> createState() => _SwitchExampleState(); } class _SwitchExampleState extends ConsumerState<SwitchExample> { late bool _localDynamicColorEnabled; @override void initState() { super.initState(); // 从Provider初始化本地状态 _localDynamicColorEnabled = ref.read(settingsProvider).isDynamicColorEnabled; } @override Widget build(BuildContext context) { return Switch( value: _localDynamicColorEnabled, activeColor: Colors.red, onChanged: (bool value) { // 1. 先更新本地状态,触发Switch动画 setState(() { _localDynamicColorEnabled = value; }); // 2. 后台异步更新SharedPreferences和Provider,无需await阻塞UI ref.read(settingsProvider.notifier).setDynamicColorEnabled(value); }, ); } }
补充:Provider侧的正确实现
确保你的SettingsNotifier正确处理异步写入逻辑:
// 假设的Settings数据类 class Settings { final bool isDynamicColorEnabled; Settings({required this.isDynamicColorEnabled}); Settings copyWith({bool? isDynamicColorEnabled}) { return Settings( isDynamicColorEnabled: isDynamicColorEnabled ?? this.isDynamicColorEnabled, ); } } class SettingsNotifier extends StateNotifier<Settings> { SettingsNotifier(Settings state) : super(state); Future<void> setDynamicColorEnabled(bool value) async { // 写入SharedPreferences final prefs = await SharedPreferences.getInstance(); await prefs.setBool('dynamic_color_enabled', value); // 更新Provider状态 state = state.copyWith(isDynamicColorEnabled: value); } } final settingsProvider = StateNotifierProvider<SettingsNotifier, Settings>((ref) { // 初始化时从SharedPreferences读取数据(可优化为异步初始化,这里简化示例) return SettingsNotifier(Settings(isDynamicColorEnabled: false)); });
内容的提问来源于stack exchange,提问作者Mervin Hemaraju
相关产品推荐
相关产品推荐

