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

Flutter:带状态的ListView.Builder滚动时如何监听最后一帧事件

解决方案

要实现滚动过程中仅在最后一帧更新列表项文本的需求,可以通过ScrollController结合SchedulerBinding来监听滚动状态并控制更新时机,具体实现如下:

核心思路

  1. 使用ScrollController监听列表滚动状态,判断是否处于滚动过程中。
  2. 借助SchedulerBinding.addPostFrameCallback,确保仅在当前渲染帧的最后阶段执行文本更新,避免滚动过程中频繁刷新UI。
  3. 维护状态变量存储显示文本,仅在合适时机触发setState更新。

完整代码实现

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final ScrollController _scrollController = ScrollController();
  // 存储每个列表项的显示文本,初始化为默认值
  final List<String> _itemTexts = List.generate(1000, (index) => 'index - $index');
  // 标记是否需要在帧结束时更新文本
  bool _needUpdate = false;

  @override
  void initState() {
    super.initState();
    // 添加滚动监听
    _scrollController.addListener(_onScroll);
  }

  void _onScroll() {
    // 当列表正在滚动时,标记需要更新
    if (_scrollController.position.isScrollingNotifier.value) {
      _needUpdate = true;
      // 注册帧结束回调,确保仅在最后一帧执行更新
      SchedulerBinding.instance.addPostFrameCallback((_) {
        if (_needUpdate) {
          setState(() {
            // 模拟更新逻辑,可根据实际需求调整
            for (int i = 0; i < 1000; i++) {
              _itemTexts[i] = 'index - $i (updated)';
            }
            _needUpdate = false;
          });
        }
      });
    }
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
        controller: _scrollController,
        itemCount: 1000,
        itemBuilder: (BuildContext context, int index) {
          return Row(
            children: [
              const Icon(Icons.list),
              SizedBox(
                height: 30,
                child: Text('  ${_itemTexts[index]}'),
              ),
            ],
          );
        },
      ),
    );
  }
}

关键细节说明

  • ScrollController监听:通过isScrollingNotifier.value判断列表是否处于滚动状态,避免非滚动场景触发更新。
  • SchedulerBinding帧回调:addPostFrameCallback会在当前帧所有Widget构建完成后执行,保证这是当前滚动周期的最后一帧更新。
  • 状态控制:使用_needUpdate标记避免重复注册回调,减少不必要的UI刷新。

如果需要在滚动完全停止后再更新文本,可以替换为监听ScrollEndNotification的方式:

// 替换原ListView部分为以下代码
body: NotificationListener<ScrollEndNotification>(
  onNotification: (notification) {
    SchedulerBinding.instance.addPostFrameCallback((_) {
      setState(() {
        // 执行文本更新逻辑
        for (int i = 0; i < 1000; i++) {
          _itemTexts[i] = 'index - $i (updated)';
        }
      });
    });
    return true;
  },
  child: ListView.builder(
    itemCount: 1000,
    itemBuilder: (BuildContext context, int index) {
      return Row(
        children: [
          const Icon(Icons.list),
          SizedBox(
            height: 30,
            child: Text('  ${_itemTexts[index]}'),
          ),
        ],
      );
    },
  ),
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 22:55:04