Flutter无限滚动插件infinite的使用
Flutter无限滚动插件infinite的使用
概述
此插件提供了列表和网格的无限视图功能。它经过优化,可以处理大量数据,特别适合渲染大量的媒体文件(如图片和视频)。
源代码
源代码可在以下地址获取: GitLab
特性
- 可以选择
<code>InfiniteViewMode.grid</code>
或<code>InfiniteViewMode.list</code>
模式。 - 可以切换当前模式。
- 切换模式时会将已获取的数据传递到新模式。
- 不需要手动编写
<code>Image</code>
或<code>Video</code>
小部件。 - 高性能处理大量媒体。
使用步骤
添加依赖
在 pubspec.yaml
文件中添加以下依赖:
dependencies:
infinite: ^1.0.0
然后在项目目录的控制台运行以下命令:
flutter pub get
环境要求
确保您的环境满足以下条件:
environment:
sdk: ">=2.12.0 <3.0.0"
使用示例
基本用法
InfiniteView
是一个状态管理小部件,用于处理列表或网格的无限滚动。您可以为其指定一个 key
并调用以下方法:
reloadMode() {
key.currentState.onReloadMode(InfiniteViewMode.list);
}
clear() {
key.currentState.clear();
}
获取数据
您需要实现 _onGetData
方法来获取数据。以下是一个示例:
Future<List<InfiniteItemViewData<MyListData>>> _onGetData(
startIndex,
nextItemsCount,
) async {
if (startIndex < 0) return [];
int endIndex = startIndex + nextItemsCount + 1;
endIndex = endIndex < items.length ? endIndex : items.length;
final items = await getItems();
return _onInitItems(items);
}
必要属性
itemsCount
是必需的,因为列表需要知道何时到达最后一页。当滚动到最后一个元素时,所有项目将在最后一页之前被获取。
如果使用 <code>InfiniteViewMode.grid</code>
,则需要提供 <code>InfiniteGridDelegate</code>
。如果使用 <code>InfiniteViewMode.list</code>
,则需要提供 <code>InfiniteListDelegate</code>
。
Delegate 示例
以下是 <code>InfiniteGridDelegate</code>
的示例:
delegateGrid: InfiniteGridDelegate(
maxWidth: size.width,
builder: (context, value, index) => Container(
color: value.color,
child: Text(value.text),
),
itemExtent: size.width / 2,
columnsCount: 3,
pageSize: 20,
),
getData: _onGetData,
onRefresh: _onRefresh,
自定义构建器
您可以在 delegate 中提供 <code>builder</code>
或 <code>builderWithMedia</code>
。当使用 <code>builderWithMedia</code>
时,会返回一个 <code>InfiniteViewMedia</code>
列表。在启动时提供 <code>InfiniteItemViewData</code>
时,您需要提供适当的 <code>InfiniteMediaData</code>
。
示例代码:
builderWithMedia: (context, value, index, media) => Container(
color: value.color,
child: Stack(
children: [
media.isNotEmpty ? media.first : Container(),
Align(
alignment: Alignment.bottomCenter,
child: Text(value.text),
),
],
),
),
回调函数
<code>onRefresh</code>
:用户拉动列表时触发自定义回调。<code>colorRefreshIndicator</code>
:设置下拉刷新指示器的颜色。<code>noMoreItemsIndicatorBuilder</code>
:用户滚动到底部时显示自定义视图。<code>noFoundItemsIndicatorBuilder</code>
:未找到任何项目时显示自定义视图。
示例代码
以下是一个完整的示例代码,展示了如何使用 <code>Infinite</code>
插件实现无限滚动:
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:infinite/infinite.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Infinite Demo',
theme: ThemeData.dark(),
themeMode: ThemeMode.dark,
home: const MyHomePage(title: 'Infinite widget'),
);
}
}
/// 数据模型
class MyListData {
MyListData({
required this.color,
required this.text,
});
final String text;
final Color color;
}
/// 主页面
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
/// 页面状态
class _MyHomePageState extends State<MyHomePage> {
final _keyInfinite = GlobalKey<InfiniteViewState>();
List<InfiniteItemViewData<MyListData>> items = [];
@override
void initState() {
items = _onCreateItems();
super.initState();
}
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Infinite.infiniteView<MyListData, InfiniteItemViewData<MyListData>>(
key: _keyInfinite,
itemsCount: items.length,
mode: InfiniteViewMode.list,
delegateList: InfiniteListDelegate(
maxWidth: size.width,
builder: (context, value, index) => Container(),
builderWithMedia: (context, value, index, media) => Container(
constraints: const BoxConstraints(minHeight: 100),
color: value.color,
child: Column(
children: [
media.isNotEmpty ? media.first : Container(),
SizedBox(height: 100, child: Center(child: Text(value.text))),
],
),
),
itemExtent: 100,
pageSize: 7,
),
delegateGrid: InfiniteGridDelegate(
maxWidth: size.width,
builderWithMedia: (context, value, index, media) => Container(
color: value.color,
child: Stack(
children: [
media.isNotEmpty ? media.first : Container(),
Align(
alignment: Alignment.bottomCenter,
child: Text(value.text),
),
],
),
),
itemExtent: size.width / 2,
columnsCount: 3,
pageSize: 20,
),
getData: _onGetData,
onRefresh: _onRefresh,
),
floatingActionButton: FloatingActionButton(onPressed: _onSwitchMode),
);
}
List<InfiniteItemViewData<MyListData>> _onCreateItems() {
return List.generate(
20000,
(index) => InfiniteItemViewData(
value: MyListData(
text: 'Hi$index',
color: _randomColor(),
),
media: [
InfiniteMediaData(
id: index.toString(),
url: 'https://storage.googleapis.com/cms-storage-bucket/6f183a9db312d0e1b535.png',
isVideo: false,
),
],
),
);
}
Future<void> _onRefresh() async {
await Future(() => items = _onCreateItems());
_keyInfinite.currentState?.clear();
setState(() {});
}
Future<List<InfiniteItemViewData<MyListData>>> _onGetData(
startIndex,
nextItemsCount,
) async {
if (startIndex < 0) return [];
int endIndex = startIndex + nextItemsCount + 1;
endIndex = endIndex < items.length ? endIndex : items.length;
return await Future(() => items.sublist(startIndex, endIndex));
}
_onSwitchMode() {
final selectedMode = _keyInfinite.currentState?.mode;
if (selectedMode != null) {
switch (selectedMode) {
case InfiniteViewMode.list:
_keyInfinite.currentState?.onReloadMode(InfiniteViewMode.grid);
break;
case InfiniteViewMode.grid:
_keyInfinite.currentState?.onReloadMode(InfiniteViewMode.list);
break;
}
}
}
Color _randomColor() {
return Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
}
}
其他信息
此插件针对长列表和大量媒体进行了优化。特别是视频播放需要设备的内存支持。如果仍然遇到问题,请在您的 <code>Info.plist</code>
文件中添加以下配置:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsForMedia</key>
<true/>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
更多关于Flutter无限滚动插件infinite的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter无限滚动插件infinite的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在 Flutter 中,实现无限滚动(Infinite Scroll)通常可以通过 ListView.builder
或 GridView.builder
结合分页逻辑来实现。不过,如果你想使用一个现成的插件来简化这个过程,infinite_scroll_pagination
是一个非常流行的选择。
1. 安装 infinite_scroll_pagination
插件
首先,在 pubspec.yaml
文件中添加依赖:
dependencies:
flutter:
sdk: flutter
infinite_scroll_pagination: ^3.2.0
然后运行 flutter pub get
来安装依赖。
2. 使用 PagedListView
实现无限滚动
以下是一个简单的例子,展示如何使用 PagedListView
实现无限滚动:
import 'package:flutter/material.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Infinite Scroll Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: InfiniteScrollExample(),
);
}
}
class InfiniteScrollExample extends StatefulWidget {
[@override](/user/override)
_InfiniteScrollExampleState createState() => _InfiniteScrollExampleState();
}
class _InfiniteScrollExampleState extends State<InfiniteScrollExample> {
static const _pageSize = 20;
final PagingController<int, String> _pagingController =
PagingController(firstPageKey: 0);
[@override](/user/override)
void initState() {
super.initState();
_pagingController.addPageRequestListener((pageKey) {
_fetchPage(pageKey);
});
}
Future<void> _fetchPage(int pageKey) async {
try {
final newItems = await _fetchItems(pageKey);
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;
}
}
Future<List<String>> _fetchItems(int startIndex) async {
// 模拟网络请求,返回数据
await Future.delayed(Duration(seconds: 1));
return List.generate(
_pageSize, (index) => 'Item ${startIndex + index + 1}');
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Infinite Scroll Example'),
),
body: PagedListView<int, String>(
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<String>(
itemBuilder: (context, item, index) => ListTile(
title: Text(item),
),
),
),
);
}
[@override](/user/override)
void dispose() {
_pagingController.dispose();
super.dispose();
}
}