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

ListView.builder构建过多项:如何实现仅为可见项加载数据?

问题原因
  1. ListView.builder的预加载机制:Flutter的ListView.builder默认会预加载超出当前可见区域的列表项(通常是前后各1-2屏的数量),目的是让滚动更流畅,避免用户滚动时出现空白。所以即使屏幕只显示8个项,它会提前构建更多项(比如你遇到的24个)。
  2. 加载逻辑无限制触发:你的代码中,只要index >= entries.length就调用addData,而初始entries是空数组,所有被预加载的index(0到23)都会触发addData,导致大量重复加载请求。同时每次setState后,builder会重新执行,进一步触发更多不必要的加载逻辑。
  3. 未设置itemCount:ListView.builder默认itemCount是无限大的,这会让它不断尝试构建更多项,直到遇到限制,这也是构建数量远超可见项的核心原因之一。
修改方案

要实现仅在滚动到列表末尾时加载数据(避免预加载过多无效项),需要做以下调整:

  • 增加加载状态变量,防止重复触发加载
  • 设置itemCount,明确列表的总项数(已加载项 + 加载占位项)
  • 仅当滚动到当前列表的末尾附近时,才触发加载逻辑

修改后的代码示例:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final List<int> entries = [];
  bool isLoading = false;
  // 模拟每页加载的数量
  final int perPage = 8;

  void addData() async {
    if (isLoading) return; // 避免重复加载
    setState(() => isLoading = true);
    
    await Future.delayed(const Duration(seconds: 2));
    // 批量添加数据,模拟分页加载
    final startIndex = entries.length;
    for (int i = 0; i < perPage; i++) {
      entries.add(startIndex + i);
    }
    
    setState(() => isLoading = false);
  }

  @override
  void initState() {
    super.initState();
    // 初始化加载第一页数据
    addData();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ListView.builder(
        itemCount: entries.length + (isLoading ? 1 : 0), // 总项数:已加载项 + 加载占位符
        itemBuilder: (BuildContext context, int index) {
          // 如果是最后一个项且正在加载,显示加载指示器
          if (index == entries.length) {
            return const SizedBox(
              height: 50,
              child: Center(child: CircularProgressIndicator()),
            );
          }
          // 触发加载的条件:滚动到倒数第2个项时加载下一页(提前加载,提升滚动体验)
          if (index == entries.length - 2 && !isLoading) {
            addData();
          }
          return SizedBox(
            height: 50,
            child: Center(child: Text('Entry ${entries[index]}')),
          );
        },
      ),
    );
  }
}
关键调整说明
  • isLoading变量:拦截重复的加载请求,避免同一时间段内发起大量无效异步操作。
  • itemCount设置:明确列表总长度,让ListView.builder知道何时停止构建多余项。
  • 加载触发时机:选择滚动到倒数第2个项时触发加载(可根据需求调整为倒数第1个),既保证滚动流畅无空白,又不会提前加载过多不必要的内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:55:24