Flutter可滚动定位列表插件scrollable_positioned_list_extended的使用
Flutter可滚动定位列表插件scrollable_positioned_list_extended的使用
概述
scrollable_positioned_list_extended
是一个Flutter插件,它允许你创建一个可以滚动到特定项的列表。它不仅提供了滚动或跳转到特定项目的能力,还允许确定当前可见的项目。
新增功能
该包最近获得了来自 scroll_to_index 的能力,用户可以通过 AutoScrollController
来操作,但存在一定的限制。
注意事项
- 这是 scrollable_positioned_list 的扩展版本,增加了如
scrollToMax
、jumpToMax
等方法,并且实现了scrollListener
以监听滚动通知的功能。
新增特性
scrollToMax
- 滚动到最大范围jumpToMax
- 跳转到最大范围scrollToMin
- 滚动到最小范围jumpToMin
- 跳转到最小范围scrollListener
- 监听ScrollNotifications
,例如当前偏移量ScrollPostition
- 访问
AutoScrollController()
- 使用ItemScrollController.getAutoScrollController
方法(需确保ItemScrollController.isAttached == true
)
AutoScrollController? _autoScrollController;
if (itemScrollController.isAttached) {
_autoScrollController = itemScrollController.getAutoScrollController;
}
使用方法
创建 ScrollablePositionedList
你可以通过以下方式创建一个 ScrollablePositionedList
:
final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();
ScrollablePositionedList.builder(
itemCount: 500,
itemBuilder: (context, index) => Text('Item $index'),
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionsListener,
);
滚动到特定项
itemScrollController.scrollTo(
index: 150,
duration: Duration(seconds: 2),
curve: Curves.easeInOutCubic,
);
跳转到特定项
itemScrollController.jumpTo(index: 150);
监听可见项
itemPositionsListener.itemPositions.addListener(() => ...);
监听滚动通知
itemScrollController.scrollListener(
(notification) {
debugPrint(notification.position.maxScrollExtent.toString());
// 处理通知
},
);
滚动到最大和最小位置
// 滚动到最大
itemScrollController.scrollToMax(
duration: Duration(seconds: 2),
curve: Curves.easeInOutCubic,
);
// 跳转到最大
itemScrollController.jumpToMax();
// 滚动到最小
itemScrollController.scrollToMin(
duration: Duration(seconds: 2),
curve: Curves.easeInOutCubic,
);
// 跳转到最小
itemScrollController.jumpToMin();
示例代码
以下是完整的示例代码,展示了如何使用 scrollable_positioned_list_extended
插件:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'package:scrollable_positioned_list_extended/scrollable_positioned_list_extended.dart';
const numberOfItems = 5001;
const minItemHeight = 20.0;
const maxItemHeight = 150.0;
const scrollDuration = Duration(seconds: 2);
const randomMax = 32;
void main() {
runApp(ScrollablePositionedListExample());
}
class ScrollablePositionedListExample extends StatelessWidget {
const ScrollablePositionedListExample({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ScrollablePositionedList Example',
theme: ThemeData(primarySwatch: Colors.blue),
home: const ScrollablePositionedListPage(),
);
}
}
class ScrollablePositionedListPage extends StatefulWidget {
const ScrollablePositionedListPage({Key? key}) : super(key: key);
@override
_ScrollablePositionedListPageState createState() => _ScrollablePositionedListPageState();
}
class _ScrollablePositionedListPageState extends State<ScrollablePositionedListPage> {
final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();
late List<double> itemHeights;
late List<Color> itemColors;
bool reversed = false;
double alignment = 0;
AutoScrollController? _autoScrollController;
@override
void initState() {
super.initState();
final heightGenerator = Random(328902348);
final colorGenerator = Random(42490823);
itemHeights = List<double>.generate(
numberOfItems,
(_) => heightGenerator.nextDouble() * (maxItemHeight - minItemHeight) + minItemHeight,
);
itemColors = List<Color>.generate(numberOfItems, (_) => Color(colorGenerator.nextInt(randomMax)).withOpacity(1));
_autoGetPosition();
}
void _autoGetPosition() {
Future.delayed(const Duration(milliseconds: 500), () {
itemScrollController.scrollListener(
(notification) {
_autoScrollController = itemScrollController.getAutoScrollController;
debugPrint(notification.position.maxScrollExtent.toString());
},
);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: OrientationBuilder(
builder: (context, orientation) => Column(
children: [
Expanded(child: list(orientation)),
positionsView,
Row(
children: [
Column(
children: [
scrollControlButtons,
const SizedBox(height: 10),
jumpControlButtons,
alignmentControl,
],
),
Column(
children: [
ElevatedButton(
onPressed: () {
itemScrollController.scrollToMax(duration: const Duration(milliseconds: 800));
},
child: const Text("Scroll To Max"),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
itemScrollController.scrollToMin(duration: const Duration(milliseconds: 800));
},
child: const Text("Scroll To Min"),
),
],
),
const SizedBox(width: 10),
Column(
children: [
ElevatedButton(
onPressed: () {
itemScrollController.jumpToMax();
},
child: const Text("Jump To Max"),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
itemScrollController.jumpToMin();
},
child: const Text("Jump To Min"),
),
],
),
const SizedBox(width: 10),
Column(
children: [
ElevatedButton(
onPressed: () {
_autoScrollController?.scrollToIndex(10);
},
child: const Text("Scroll To Index Via Scroll_To_Index"),
),
const SizedBox(height: 10),
],
),
],
)
],
),
),
);
}
Widget get alignmentControl => Row(
mainAxisSize: MainAxisSize.max,
children: [
const Text('Alignment: '),
SizedBox(
width: 200,
child: SliderTheme(
data: SliderThemeData(showValueIndicator: ShowValueIndicator.always),
child: Slider(
value: alignment,
label: alignment.toStringAsFixed(2),
onChanged: (double value) => setState(() => alignment = value),
),
),
),
],
);
Widget list(Orientation orientation) => ScrollablePositionedList.builder(
itemCount: numberOfItems,
itemBuilder: (context, index) => item(index, orientation),
itemScrollController: itemScrollController,
addAutomaticKeepAlives: false,
minCacheExtent: 0,
itemPositionsListener: itemPositionsListener,
reverse: reversed,
scrollDirection: Axis.vertical,
);
Widget get positionsView => ValueListenableBuilder<Iterable<ItemPosition>>(
valueListenable: itemPositionsListener.itemPositions,
builder: (context, positions, child) {
int? min;
int? max;
if (positions.isNotEmpty) {
min = positions
.where((position) => position.itemTrailingEdge > 0)
.reduce((min, position) => position.itemTrailingEdge < min.itemTrailingEdge ? position : min)
.index;
max = positions
.where((position) => position.itemLeadingEdge < 1)
.reduce((max, position) => position.itemLeadingEdge > max.itemLeadingEdge ? position : max)
.index;
}
return Row(
children: [
Expanded(child: Text('First Item: ${min ?? ''}')),
Expanded(child: Text('Last Item: ${max ?? ''}')),
const Text('Reversed: '),
Checkbox(
value: reversed,
onChanged: (bool? value) => setState(() => reversed = value!),
)
],
);
},
);
Widget get scrollControlButtons => Row(
children: [
const Text('scroll to'),
scrollButton(0),
scrollButton(5),
scrollButton(10),
scrollButton(99),
scrollButton(5000),
],
);
Widget get jumpControlButtons => Row(
children: [
const Text('jump to'),
jumpButton(0),
jumpButton(5),
jumpButton(10),
jumpButton(99),
jumpButton(5000),
],
);
final _scrollButtonStyle = ButtonStyle(
padding: MaterialStateProperty.all(const EdgeInsets.symmetric(horizontal: 20, vertical: 0)),
minimumSize: MaterialStateProperty.all(Size.zero),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
);
Widget scrollButton(int value) => TextButton(
key: ValueKey<String>('Scroll$value'),
onPressed: () {
scrollTo(value);
},
child: Text('$value'),
style: _scrollButtonStyle,
);
Widget jumpButton(int value) => TextButton(
key: ValueKey<String>('Jump$value'),
onPressed: () {
jumpTo(value);
},
child: Text('$value'),
style: _scrollButtonStyle,
);
void scrollTo(int index) async {
await itemScrollController.scrollTo(
index: index,
duration: scrollDuration,
curve: Curves.easeInCubic,
alignment: alignment,
);
}
void jumpTo(int index) => itemScrollController.jumpTo(index: index, alignment: alignment);
Widget item(int i, Orientation orientation) {
return SizedBox(
height: 200,
child: Column(
children: [
Expanded(
child: Container(
color: Colors.grey[400],
child: Center(
child: Text('Item $i'),
),
),
),
Container(
height: 80,
color: Colors.amber,
)
],
),
);
}
}
限制
ItemScrollController.getAutoScrollController
不适用于以下方法:highlight()
cancelAllHighlights()
jumpTo()
希望这些信息对你有所帮助!如果你有任何问题或需要进一步的帮助,请随时提问。
更多关于Flutter可滚动定位列表插件scrollable_positioned_list_extended的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
1 回复