You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 11:55:27