Flutter 颤振列表视图延迟加载
如何实现无限列表视图的项目延迟加载?当用户滚动到listview的末尾时,我想通过网络加载更多项目。您可以收听广播Flutter 颤振列表视图延迟加载,flutter,Flutter,如何实现无限列表视图的项目延迟加载?当用户滚动到listview的末尾时,我想通过网络加载更多项目。您可以收听广播 ScrollController有一些有用的信息,例如scrolloffset和列表 在您的例子中,有趣的部分位于当前可见的滚动位置controller.position。它表示可滚动文件的一段 ScrollPosition包含有关其在可滚动文件中位置的信息。例如extentBefore和extentAfter。或者它的大小,带有extentInside 考虑到这一点,您可以基于表
ScrollController
有一些有用的信息,例如scrolloffset和列表
在您的例子中,有趣的部分位于当前可见的滚动位置controller.position
。它表示可滚动文件的一段
ScrollPosition
包含有关其在可滚动文件中位置的信息。例如extentBefore
和extentAfter
。或者它的大小,带有extentInside
考虑到这一点,您可以基于表示剩余可用滚动空间的extentAfter
触发服务器调用
下面是一个使用我所说内容的基本示例
class MyHome extends StatefulWidget {
@override
_MyHomeState createState() => new _MyHomeState();
}
class _MyHomeState extends State<MyHome> {
ScrollController controller;
List<String> items = new List.generate(100, (index) => 'Hello $index');
@override
void initState() {
super.initState();
controller = new ScrollController()..addListener(_scrollListener);
}
@override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Scrollbar(
child: new ListView.builder(
controller: controller,
itemBuilder: (context, index) {
return new Text(items[index]);
},
itemCount: items.length,
),
),
);
}
void _scrollListener() {
print(controller.position.extentAfter);
if (controller.position.extentAfter < 500) {
setState(() {
items.addAll(new List.generate(42, (index) => 'Inserted $index'));
});
}
}
}
类MyHome扩展StatefulWidget{
@凌驾
_MyHomeState createState()=>new_MyHomeState();
}
类MyHomeState扩展状态{
滚动控制器;
列表项=新列表。生成(100,(索引)=>“Hello$index”);
@凌驾
void initState(){
super.initState();
控制器=新的ScrollController()…addListener(\u scrollListener);
}
@凌驾
无效处置(){
控制器。RemovelListener(_scrollListener);
super.dispose();
}
@凌驾
小部件构建(构建上下文){
归还新脚手架(
正文:新的滚动条(
子项:新建ListView.builder(
控制器:控制器,
itemBuilder:(上下文,索引){
返回新文本(项目[索引]);
},
itemCount:items.length,
),
),
);
}
void_scrollListener(){
打印(控制器、位置、延伸器);
if(控制器位置延伸小于500){
设置状态(){
items.addAll(newlist.generate(42,(index)=>Inserted$index));
});
}
}
}
您可以清楚地看到,当到达滚动的末尾时,滚动条会因为加载了更多的项目而消耗。感谢Rémi Rousselet的方法,但它并没有解决所有问题。尤其是当ListView滚动到底部时,它仍然会调用scrollListener几次。改进的方法是将通知侦听器与Remi的方法相结合。以下是我的解决方案:
bool _handleScrollNotification(ScrollNotification notification) {
if (notification is ScrollEndNotification) {
if (_controller.position.extentAfter == 0) {
loadMore();
}
}
return false;
}
@override
Widget build(BuildContext context) {
final Widget gridWithScrollNotification = NotificationListener<
ScrollNotification>(
onNotification: _handleScrollNotification,
child: GridView.count(
controller: _controller,
padding: EdgeInsets.all(4.0),
// Create a grid with 2 columns. If you change the scrollDirection to
// horizontal, this would produce 2 rows.
crossAxisCount: 2,
crossAxisSpacing: 2.0,
mainAxisSpacing: 2.0,
// Generate 100 Widgets that display their index in the List
children: _documents.map((doc) {
return GridPhotoItem(
doc: doc,
);
}).toList()));
return new Scaffold(
key: _scaffoldKey,
body: RefreshIndicator(
onRefresh: _handleRefresh, child: gridWithScrollNotification));
}
bool\u handleScrollNotification(滚动通知通知){
如果(通知为ScrollEndNotification){
如果(_controller.position.extentAfter==0){
loadMore();
}
}
返回false;
}
@凌驾
小部件构建(构建上下文){
最终小部件GridWithCrollNotification=NotificationListener<
滚动通知>(
onNotification:_handleScrollNotification,
子项:GridView.count(
控制器:_控制器,
填充:所有边缘设置(4.0),
//创建一个包含两列的网格。如果将滚动方向更改为
//水平,这将产生2行。
交叉轴计数:2,
交叉轴间距:2.0,
主轴间距:2.0,
//生成100个在列表中显示其索引的小部件
子项:_documents.map((doc){
退货项目(
博士:博士,
);
}).toList());
归还新脚手架(
钥匙:_scaffoldKey,
正文:刷新指示器(
onRefresh:_handleRefresh,child:gridWithScrollNotification));
}
解决方案使用了ScrollController,我看到了关于页面的评论
我想分享我关于包增量加载列表视图的发现
.
正如packaged所说:这可以用来加载从API请求接收的分页数据
基本上,当ListView构建最后一项时,这意味着用户已向下滚动到底部
希望它能帮助有类似问题的人。
为了演示的目的,我改变了示例,让一个页面只包含一个项目
并添加一个循环压缩机指示器
使用lazy_load_scrollview:1.0.0包,该包在幕后使用了与熊猫世界在这里回答的相同的概念。该软件包使其更易于实现。如果您希望实现上下方向的延迟加载,则发布的解决方案无法解决此问题。滚动将在此处跳转,请参见
如果你想做上下方向的惰性加载,库可以提供帮助
示例():
静态常数双套件高度=30.0;
双向交叉控制器;
双oldScrollPosition=0.0;
@凌驾
void initState(){
super.initState();
for(int i=-10;i正边界)
{
对于(inti=itemCount+1;i,这里是我的方法,其灵感来自上述答案
NotificationListener(onNotification: _onScrollNotification, child: GridView.builder())
bool _onScrollNotification(ScrollNotification notification) {
if (notification is ScrollEndNotification) {
final before = notification.metrics.extentBefore;
final max = notification.metrics.maxScrollExtent;
if (before == max) {
// load next page
// code here will be called only if scrolled to the very bottom
}
}
return false;
}
下面是我的查找列表视图结尾的解决方案
_scrollController.addListener(scrollListenerMilli);
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
getMoreData();
}
如果您想在1/2或3/4之后延迟加载,请这样更改
if (_scrollController.position.pixels == (_scrollController.position.maxScrollExtent * .75)) {//.5
getMoreData();
}
被接受的答案是正确的,但您也可以按如下操作:
Timer _timer;
Widget chatMessages() {
_timer = new Timer(const Duration(milliseconds: 300), () {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
});
return StreamBuilder(
stream: chats,
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
// physics: NeverScrollableScrollPhysics(),
controller: _scrollController,
shrinkWrap: true,
reverse: false,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
return MessageTile(
message: snapshot.data.documents[index].data["message"],
sendByMe: widget.sendByid ==
snapshot.data.documents[index].data["sendBy"],
);
})
: Container();
},
);
}
还有这个包,去掉了样板文件:UseListView.builder()
并提供一些比已加载的内容大的项目。当用户滚动到尚未加载的索引时,您将加载数据并重新呈现列表。@GünterZöchbauer我不喜欢这种方法,因为分页要困难得多。例如,您不知道未知索引是否在第n+1页或第n+2页内。它是这取决于用例。它在我们的项目中运行得很好。你也可以将它与滚动位置相结合。我喜欢的是,我可以拥有比加载的项目多得多的数字,滚动条反映了这一点。@GünterZöchbauer你能给我一个如何按你的方式分页的例子吗?是的,它看起来不错,我会尝试。但我有问题。itemCount(itemBuilder参数)会随着items.length的更改而动态更改吗?顺便说一句,我应该总是在函数体的末尾调用重写函数的“super”调用吗?这有点离谱,但我非常担心
if (_scrollController.position.pixels == (_scrollController.position.maxScrollExtent * .75)) {//.5
getMoreData();
}
Timer _timer;
Widget chatMessages() {
_timer = new Timer(const Duration(milliseconds: 300), () {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
});
return StreamBuilder(
stream: chats,
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
// physics: NeverScrollableScrollPhysics(),
controller: _scrollController,
shrinkWrap: true,
reverse: false,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
return MessageTile(
message: snapshot.data.documents[index].data["message"],
sendByMe: widget.sendByid ==
snapshot.data.documents[index].data["sendBy"],
);
})
: Container();
},
);
}