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

Flutter中如何为ListView.builder添加加载Spinner?

解决Flutter ListView懒加载同步计算的加载状态显示问题

核心问题

你的同步计算逻辑阻塞了主线程,导致EasyLoading的UI更新被卡住——主线程被耗时计算占用时,无法处理渲染请求,所以加载提示根本显示不出来。

解决方案

把耗时的同步计算移到**Isolate(隔离区)**中执行,让主线程专注于UI渲染。Flutter提供了compute函数简化Isolate的使用,无需手动管理隔离区通信。同时添加加载状态标记,防止重复触发计算。

修改后的完整代码

import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';

class Matches extends StatefulWidget {
  // 替换为你的Iterator生成逻辑,这里用数据源列表示例(可根据实际情况调整)
  final List<String> dataSource;

  Matches(this.dataSource);

  @override
  MatchesState createState() => MatchesState(dataSource);
}

class MatchesState extends State<Matches> {
  final List<String> _dataSource;
  final _matches = <String>[];
  int _currentOffset = 0;
  bool _isLoading = false;

  MatchesState(this._dataSource);

  Future<void> _next() async {
    // 防止重复加载或已加载完毕
    if (_isLoading || _currentOffset >= _dataSource.length) return;
    
    _isLoading = true;
    EasyLoading.show(status: 'Searching...');
    
    // 计算本次要加载的数量
    final takeCount = 10;
    final endOffset = _currentOffset + takeCount;
    final targetItems = _dataSource.sublist(
      _currentOffset, 
      endOffset > _dataSource.length ? _dataSource.length : endOffset
    );

    // 使用compute将耗时计算移到Isolate执行
    final newMatches = await compute(_processItems, targetItems);

    setState(() {
      _matches.addAll(newMatches);
      _currentOffset += newMatches.length;
      _isLoading = false;
    });

    // 更新加载提示状态
    if (_currentOffset >= _dataSource.length) {
      EasyLoading.showSuccess('搜索完成');
    } else {
      EasyLoading.dismiss(animation: false);
    }
  }

  // 顶层/静态函数:用于在Isolate中执行耗时同步计算(不能是类实例方法)
  static List<String> _processItems(List<String> items) {
    final results = <String>[];
    for (var item in items) {
      // 这里替换为你原来的耗时同步计算逻辑
      // 示例模拟耗时操作
      final processedItem = item.toUpperCase();
      sleep(const Duration(milliseconds: 100));
      results.add(processedItem);
    }
    return results;
  }

  Widget _buildMatches() {
    return ListView.builder(
      padding: const EdgeInsets.all(16.0),
      itemBuilder: (context, i) {
        if (i.isOdd) return const Divider();
        
        final index = i ~/ 2;
        // 滚动到列表末尾时触发加载
        if (index >= _matches.length && !_isLoading) {
          _next();
        }

        // 加载中且已到现有列表末尾,显示本地加载指示器(可选)
        if (index >= _matches.length) {
          return const Center(child: CircularProgressIndicator());
        }

        return ListTile(title: Text(_matches[index]));
      },
      // 动态设置列表长度,让ListView知道有更多元素待加载
      itemCount: _matches.length * 2 + (_isLoading ? 2 : 0),
    );
  }

  @override
  Widget build(BuildContext context) {
    return FlutterEasyLoading(
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Matches'),
        ),
        body: _buildMatches(),
      ),
    );
  }
}

关键调整点

  • Isolate执行计算:用compute把耗时的同步计算移到后台,主线程不阻塞,EasyLoading能正常显示。
  • 加载状态控制:添加_isLoading标记,避免滚动时重复触发加载请求。
  • 列表长度动态化:itemCount包含加载状态对应的占位元素,确保ListView能滚动到触发加载的位置。
  • 兼容原有逻辑:_processItems函数完全复用你原来的同步计算代码,无需修改核心逻辑。

内容的提问来源于stack exchange,提问作者Graham Wheeler

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 05:45:31