flutter获取listview可视区域的firstIndex和lastIndex,不破坏原有listview
Posted 庄童
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flutter获取listview可视区域的firstIndex和lastIndex,不破坏原有listview相关的知识,希望对你有一定的参考价值。
一种侵入性不强的方案,解决获取listview可视firstIndex和lastIndex问题。
无需修改已有项目代码 套上ScrollIndexWidget即可,代码如下
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
typedef ViewPortCallback = void Function(int firstIndex, int lastIndex);
class ScrollIndexWidget extends StatelessWidget {
final ScrollView child;
final ViewPortCallback callback;
const ScrollIndexWidget(
{Key? key, required this.child, required this.callback})
: super(key: key);
@override
Widget build(BuildContext context) {
return NotificationListener(child: child, onNotification: _onNotification);
}
bool _onNotification(ScrollNotification notice) {
final SliverMultiBoxAdaptorElement sliverMultiBoxAdaptorElement =
findSliverMultiBoxAdaptorElement(notice.context! as Element)!;
final viewportDimension = notice.metrics.viewportDimension;
int firstIndex = 0;
int lastIndex = 0;
void onVisitChildren(Element element) {
final SliverMultiBoxAdaptorParentData oldParentData =
element.renderObject?.parentData as SliverMultiBoxAdaptorParentData;
double layoutOffset = oldParentData.layoutOffset!;
double pixels = notice.metrics.pixels;
double all = pixels + viewportDimension;
if (layoutOffset >= pixels) {
///first和last是不同item
firstIndex = min(firstIndex, oldParentData.index! - 1);
if (layoutOffset <= all) {
lastIndex = max(lastIndex, oldParentData.index!);
}
firstIndex = max(firstIndex, 0);
} else {
///first和last是同一个item
lastIndex = firstIndex = oldParentData.index!;
}
}
sliverMultiBoxAdaptorElement.visitChildren(onVisitChildren);
callback(
firstIndex,
lastIndex,
);
return false;
}
SliverMultiBoxAdaptorElement? findSliverMultiBoxAdaptorElement(
Element element) {
if (element is SliverMultiBoxAdaptorElement) {
return element;
}
SliverMultiBoxAdaptorElement? target;
element.visitChildElements((child) {
target = findSliverMultiBoxAdaptorElement(child);
});
return target;
}
}
使用方式
import 'package:flitter_okgo/index_listen.dart';
import 'package:flutter/material.dart';
class IndexPage extends StatefulWidget {
@override
_IndexPageState createState() => _IndexPageState();
}
class _IndexPageState extends State<IndexPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('indexPage'),
),
body: ScrollIndexWidget(
child: ListView.builder(
itemBuilder: (c, i) {
return Container(
alignment: Alignment.center,
color: Colors.green.withBlue((i + 1) * 100),
height: (i + 1) * 20,
child: Text('index==$i'),
);
},
scrollDirection: Axis.vertical,
itemCount: 100,
),
callback: (first, last) {
print('当前第一个可见元素下标 $first 当前最后一个可见元素下标 $last');
},
),
);
}
}
以上是关于flutter获取listview可视区域的firstIndex和lastIndex,不破坏原有listview的主要内容,如果未能解决你的问题,请参考以下文章
无法在 Flutter 的 listview.builder 中获取长度
如何从 Listview.builder 中获取模型类 Flutter 的列表索引
Flutter:在动画的、定位的容器中获取 ListView,作为堆栈的一部分
在 Flutter 中将 Firebase 数据作为 Listview 构建器获取