Flutter 应用中的无限列表
Posted
技术标签:
【中文标题】Flutter 应用中的无限列表【英文标题】:Infinite List in Flutter Application 【发布时间】:2019-04-06 11:30:30 【问题描述】:我正在将我的应用程序从 android 迁移到颤振,直到现在我已经在颤振中使用了 ListView。我的问题是,是否有任何专门的技术可以处理大量数据?作为参考,您可以查看android RecyclerView。它处理内存中的视图并回收其运行时。那么如何在 Flutter 中实现 RecyclerView 之类的功能呢?还是颤振没有必要?
【问题讨论】:
使用ListView.builder
Flutter ListView
类似于 android 中的 ListView。 ListView.builder
类似于 RecyclerView。
Write Your First Flutter App 以ListView.builder
为例,但您可以获取更多关于Working with long lists here 的信息
【参考方案1】:
下面是一个基于chemamolins 答案的简单无限列表小部件。它接受itemBuilder
来构建当前项目,并接受onRequest
回调以在用户滚动到底部时请求更多数据。
import 'package:flutter/material.dart';
typedef Future<List<T>> RequestFn<T>(int nextIndex);
typedef Widget ItemBuilder<T>(BuildContext context, T item, int index);
class InifiniteList<T> extends StatefulWidget
final RequestFn<T> onRequest;
final ItemBuilder<T> itemBuilder;
const InifiniteList(
Key? key, required this.onRequest, required this.itemBuilder)
: super(key: key);
@override
_InifiniteListState<T> createState() => _InifiniteListState<T>();
class _InifiniteListState<T> extends State<InifiniteList<T>>
List<T> items = [];
bool end = false;
_getMoreItems() async
final moreItems = await widget.onRequest(items.length);
if (!mounted) return;
if (moreItems.isEmpty)
setState(() => end = true);
return;
setState(() => items = [...items, ...moreItems]);
@override
Widget build(BuildContext context)
return ListView.builder(
itemBuilder: (context, index)
if (index < items.length)
return widget.itemBuilder(context, items[index], index);
else if (index == items.length && end)
return const Center(child: Text('End of list'));
else
_getMoreItems();
return const SizedBox(
height: 80,
child: Center(child: CircularProgressIndicator()),
);
,
itemCount: items.length + 1,
);
用法
child: InifiniteList<String>(
onRequest: requestItems,
itemBuilder: (context, item, index) => Container(
padding: const EdgeInsets.all(30),
color: index % 2 == 0 ? Colors.purple.shade100 : Colors.lime.shade100,
child: Text(item, style: Theme.of(context).textTheme.headline6),
),
),
// normally this is the place where you request the next batch of items
// on the network.
Future<List<String>> requestItems(int nextIndex)
const pageSize = 15;
var result = List<String>.generate(pageSize, (i) => "Item: $nextIndex + i + 1");
return Future<List<String>>.delayed(
const Duration(milliseconds: 500),
() => result,
);
Live Demo
【讨论】:
【参考方案2】:最简单的方法是使用ListView.builder
而不指定itemCount
参数。
这是最简单的例子:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return new MaterialApp(
home: new MyHomePage(),
);
class MyHomePage extends StatefulWidget
@override
_MyHomePageState createState() => new _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
@override
Widget build(BuildContext context)
return new Scaffold(
appBar: new AppBar(
title: new Text("Infinite List"),
),
body: ListView.builder(
itemBuilder: (context, index)
return Text("$index");
,
),
);
稍后,您可以通过获取真实数据来增强此功能。您可以在等待新数据时在列表的最后一项中显示“CircularProgressIndicator”。
body: ListView.builder(
itemBuilder: (context, index)
if (index < data.length)
// Show your info
return Text("$index");
else
getMoreData();
return Center(child: CircularProgressIndicator());
,
itemCount: data.length + 1,
),
您可以看到我们通过添加索引来欺骗列表,并在显示最终索引时调用更多数据。
getMoreData()
将包括对setState()
的调用以强制重建并考虑新数据。
【讨论】:
我已经为包含真实数据的无限列表添加了一些解释。【参考方案3】:对于无限滚动 ListView 使用 infinite_scroll_pagination 包,此包管理用户向下滚动屏幕时的延迟加载和显示页面。
添加依赖
dependencies:
flutter:
sdk: flutter
infinite_scroll_pagination: ^2.3.0
在文件顶部向新库添加导入:
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
使用示例
class CharacterListView extends StatefulWidget
@override
_CharacterListViewState createState() => _CharacterListViewState();
class _CharacterListViewState extends State<CharacterListView>
static const _pageSize = 20;
final PagingController<int, CharacterSummary> _pagingController =
PagingController(firstPageKey: 0);
@override
void initState()
_pagingController.addPageRequestListener((pageKey)
_fetchPage(pageKey);
);
super.initState();
Future<void> _fetchPage(int pageKey) async
try
final newItems = await RemoteApi.getCharacterList(pageKey, _pageSize);
final isLastPage = newItems.length < _pageSize;
if (isLastPage)
_pagingController.appendLastPage(newItems);
else
final nextPageKey = pageKey + newItems.length;
_pagingController.appendPage(newItems, nextPageKey);
catch (error)
_pagingController.error = error;
@override
Widget build(BuildContext context) =>
// Don't worry about displaying progress or error indicators on screen; the
// package takes care of that. If you want to customize them, use the
// [PagedChildBuilderDelegate] properties.
PagedListView<int, CharacterSummary>(
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<CharacterSummary>(
itemBuilder: (context, item, index) => CharacterListItem(
character: item,
),
),
);
@override
void dispose()
_pagingController.dispose();
super.dispose();
【讨论】:
【参考方案4】:显示数据列表是移动应用的基本模式。 Flutter 包含 ListView 小部件,使处理列表变得轻而易举。
我已经通过以下步骤解决了这个问题
-
使用 ListView 小部件
ListView类有四个构造函数
您必须使用 Builder 构造函数 (ListView.builder)
当您必须按需制作元素列表时,使用 Builder 构造函数
适用于具有大量(或无限)子级的列表视图
在这里您可以观看解决方案视频CLICK HERE
【讨论】:
以上是关于Flutter 应用中的无限列表的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Flutter 从 Firestore 中的 ListView 获得无限滚动
在 Flutter 中使用 Cloud Firestore 创建无限列表