Flutter条件渲染异常:短暂显示错误Widget后自动修正
问题原因
这是因为Provider初始化时,异步加载SharedPreferences数据的过程导致了初始状态与最终状态的短暂不一致:
- Tasks类初始化时,
_tasks默认是空数组,此时UI会根据tasks.isEmpty显示"No tasks"。 - 随后
syncDataWithProvider异步完成,从SharedPreferences加载数据并更新_tasks,调用notifyListeners()触发UI重建,才显示正确的任务列表。 - 这个异步过程的时间差就造成了错误Widget的短暂显示。
修复方案
1. 在Provider中添加加载状态标记
修改Tasks类,增加加载状态变量,确保异步加载完成前不判断任务是否为空:
class Tasks with ChangeNotifier { List<Task> _tasks = []; // 新增加载状态,初始为true bool _isLoading = true; Tasks() { initialState(); } List get tasks => _tasks; bool get isLoading => _isLoading; // 提供加载状态的getter void initialState() { syncDataWithProvider(); } // 保留原有add/delete/edit等方法... Future syncDataWithProvider() async { SharedPreferences prefs = await SharedPreferences.getInstance(); var result = prefs.getStringList('tasks'); if (result != null) { _tasks = result.map((task) => Task.fromJson(json.decode(task))).toList(); } // 加载完成后更新状态并通知UI _isLoading = false; notifyListeners(); } }
2. 修改UI层的条件渲染逻辑
先判断加载状态,加载中显示加载指示器,加载完成后再根据任务列表是否为空显示对应Widget:
// 先获取Provider实例,避免多次watch final tasksProvider = context.watch<Tasks>(); if (tasksProvider.isLoading) { // 加载中显示加载指示器,也可以自定义其他加载UI return const Center(child: CircularProgressIndicator()); } else { return tasksProvider.tasks.isEmpty ? const Center( child: Text( 'No tasks', style: TextStyle(fontSize: 20), ), ) : Expanded( child: Column( children: [ const Center( child: Text( "Tasks", style: TextStyle(fontSize: 20), ), ), const SizedBox(height: 20.0), ListView.builder( scrollDirection: Axis.vertical, shrinkWrap: true, itemCount: tasksProvider.tasks.length, itemBuilder: (context, index) { final Task task = tasksProvider.tasks[index]; return TaskWidget(task: task); }, ), ], ), ); }
额外优化点
- 避免在UI中多次调用
context.watch<Tasks>(),先获取一次实例复用,减少不必要的监听重建。 edit方法可以简化:不需要重新创建新列表,直接修改原列表中的元素后调用notifyListeners()即可(List是引用类型,修改元素后需通知UI更新)。
内容的提问来源于stack exchange,提问作者bringand1
相关产品推荐
相关产品推荐

