Flutter可滚动定位列表插件scrollable_positioned_list_nic的使用
Flutter可滚动定位列表插件scrollable_positioned_list_nic的使用
ScrollablePositionedList
是一个 Flutter 列表控件,它允许你将列表滚动到特定的项目,并且可以确定哪些项目当前在屏幕上可见。
使用方法
ScrollablePositionedList
的使用方式类似于 ListView
的构建器版本,但具有滚动或跳转到特定项目的功能。
示例
首先,我们需要创建一些控制器来管理滚动和项目位置:
final ItemScrollController itemScrollController = ItemScrollController();
final ScrollOffsetController scrollOffsetController = ScrollOffsetController();
final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();
final ScrollOffsetListener scrollOffsetListener = ScrollOffsetListener.create();
然后,我们可以创建一个 ScrollablePositionedList
:
ScrollablePositionedList.builder(
itemCount: numberOfItems,
itemBuilder: (context, index) => item(index, orientation),
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionsListener,
scrollOffsetController: scrollOffsetController,
reverse: reversed,
scrollDirection: orientation == Orientation.portrait ? Axis.vertical : Axis.horizontal,
);
我们可以通过以下方式滚动到特定的项目:
itemScrollController.scrollTo(
index: 150,
duration: Duration(seconds: 2),
curve: Curves.easeInOutCubic,
);
或者直接跳转到特定的项目:
itemScrollController.jumpTo(index: 150);
我们还可以监听哪些项目当前在屏幕上可见:
itemPositionsListener.itemPositions.addListener(() {
// 处理逻辑
});
完整示例代码
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:scrollable_positioned_list_nic/scrollable_positioned_list_nic.dart';
const numberOfItems = 5001;
const minItemHeight = 20.0;
const maxItemHeight = 150.0;
const scrollDuration = Duration(seconds: 2);
const randomMax = 1 << 32;
void main() {
runApp(ScrollablePositionedListExample());
}
class ScrollablePositionedListExample extends StatelessWidget {
const ScrollablePositionedListExample({Key? key}) : super(key: key);
[@override](/user/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](/user/override)
_ScrollablePositionedListPageState createState() => _ScrollablePositionedListPageState();
}
class _ScrollablePositionedListPageState extends State<ScrollablePositionedListPage> {
final ItemScrollController itemScrollController = ItemScrollController();
final ScrollOffsetController scrollOffsetController = ScrollOffsetController();
final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();
late List<double> itemHeights;
late List<Color> itemColors;
bool reversed = false;
double alignment = 0;
[@override](/user/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));
}
[@override](/user/override)
Widget build(BuildContext context) => Material(
child: OrientationBuilder(
builder: (context, orientation) => Column(
children: [
Expanded(
child: list(orientation),
),
positionsView,
Row(
mainAxisSize: MainAxisSize.min,
children: [
Column(
children: [
scrollControlButtons,
scrollOffsetControlButtons,
const SizedBox(height: 10),
jumpControlButtons,
alignmentControl,
],
),
],
)
],
),
),
);
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,
itemPositionsListener: itemPositionsListener,
scrollOffsetController: scrollOffsetController,
reverse: reversed,
scrollDirection: orientation == Orientation.portrait ? Axis.vertical : Axis.horizontal,
);
Widget get positionsView => ValueListenableBuilder<Iterable<ItemPosition>>(
valueListenable: itemPositionsListener.itemPositions,
builder: (context, positions, child) {
int? min;
int? max;
if (positions.isNotEmpty) {
min = positions
.where((ItemPosition position) => position.itemTrailingEdge > 0)
.reduce((ItemPosition min, ItemPosition position) => position.itemTrailingEdge < min.itemTrailingEdge ? position : min)
.index;
max = positions
.where((ItemPosition position) => position.itemLeadingEdge < 1)
.reduce((ItemPosition max, ItemPosition 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'),
scrollItemButton(0),
scrollItemButton(5),
scrollItemButton(10),
scrollItemButton(100),
scrollItemButton(1000),
scrollItemButton(5000),
],
);
Widget get scrollOffsetControlButtons => Row(
children: [
const Text('scroll by'),
scrollOffsetButton(-1000),
scrollOffsetButton(-100),
scrollOffsetButton(-10),
scrollOffsetButton(10),
scrollOffsetButton(100),
scrollOffsetButton(1000),
],
);
Widget get jumpControlButtons => Row(
children: [
const Text('jump to'),
jumpButton(0),
jumpButton(5),
jumpButton(10),
jumpButton(100),
jumpButton(1000),
jumpButton(5000),
],
);
ButtonStyle _scrollButtonStyle({required double horizonalPadding}) => ButtonStyle(
padding: MaterialStateProperty.all(
EdgeInsets.symmetric(horizontal: horizonalPadding, vertical: 0),
),
minimumSize: MaterialStateProperty.all(Size.zero),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
);
Widget scrollItemButton(int value) => TextButton(
key: ValueKey<String>('Scroll$value'),
onPressed: () => scrollTo(value),
child: Text('$value'),
style: _scrollButtonStyle(horizonalPadding: 20),
);
Widget scrollOffsetButton(int value) => TextButton(
key: ValueKey<String>('Scroll$value'),
onPressed: () => scrollBy(value.toDouble()),
child: Text('$value'),
style: _scrollButtonStyle(horizonalPadding: 10),
);
Widget scrollPixelButton(int value) => TextButton(
key: ValueKey<String>('Scroll$value'),
onPressed: () => scrollTo(value),
child: Text('$value'),
style: _scrollButtonStyle(horizonalPadding: 20),
);
Widget jumpButton(int value) => TextButton(
key: ValueKey<String>('Jump$value'),
onPressed: () => jumpTo(value),
child: Text('$value'),
style: _scrollButtonStyle(horizonalPadding: 20),
);
void scrollTo(int index) => itemScrollController.scrollTo(index: index, duration: scrollDuration, curve: Curves.easeInOutCubic, alignment: alignment);
void scrollBy(double offset) => scrollOffsetController.animateScroll(offset: offset, duration: scrollDuration, curve: Curves.easeInOutCubic);
void jumpTo(int index) => itemScrollController.jumpTo(index: index, alignment: alignment);
Widget item(int i, Orientation orientation) {
return SizedBox(
height: orientation == Orientation.portrait ? itemHeights[i] : null,
width: orientation == Orientation.landscape ? itemHeights[i] : null,
child: Container(
color: itemColors[i],
child: Center(
child: Text('Item $i'),
),
),
);
}
}
更多关于Flutter可滚动定位列表插件scrollable_positioned_list_nic的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter可滚动定位列表插件scrollable_positioned_list_nic的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
scrollable_positioned_list_nic
是 Flutter 中的一个插件,用于实现可滚动且支持精确定位的列表。它是对 Flutter 自带的 ListView
的增强版本,允许你通过索引来精确地滚动到列表中的特定位置,甚至可以在列表中实现诸如“跳转到第 N 项”或“滚动到指定位置并保持对齐”等高级功能。
安装
首先,你需要在 pubspec.yaml
文件中添加依赖项:
dependencies:
flutter:
sdk: flutter
scrollable_positioned_list_nic: ^0.1.0
然后运行 flutter pub get
来安装依赖。
基本用法
以下是一个简单的示例,展示如何使用 scrollable_positioned_list_nic
:
import 'package:flutter/material.dart';
import 'package:scrollable_positioned_list_nic/scrollable_positioned_list_nic.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('ScrollablePositionedList Example')),
body: ScrollablePositionedListExample(),
),
);
}
}
class ScrollablePositionedListExample extends StatefulWidget {
@override
_ScrollablePositionedListExampleState createState() =>
_ScrollablePositionedListExampleState();
}
class _ScrollablePositionedListExampleState
extends State<ScrollablePositionedListExample> {
final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionsListener =
ItemPositionsListener.create();
@override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
onPressed: () {
itemScrollController.scrollTo(
index: 50,
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
);
},
child: Text('Scroll to Item 50'),
),
Expanded(
child: ScrollablePositionedList.builder(
itemCount: 100,
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionsListener,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
),
),
],
);
}
}
主要组件和功能
-
ScrollablePositionedList.builder
:itemCount
: 列表中的项目总数。itemBuilder
: 构建列表项的构建器函数。itemScrollController
: 用于控制列表滚动的控制器。itemPositionsListener
: 用于监听列表项位置的监听器。
-
ItemScrollController
:scrollTo
: 滚动到指定索引的项目。jumpTo
: 立即跳转到指定索引的项目。
-
ItemPositionsListener
:- 用于监听当前可见的列表项的位置。
高级用法
- 初始滚动位置: 你可以通过
initialScrollIndex
参数来设置列表的初始滚动位置。 - 对齐方式: 在
scrollTo
方法中,你可以通过alignment
参数来指定滚动后的对齐方式,例如0.0
表示顶部对齐,0.5
表示居中,1.0
表示底部对齐。
itemScrollController.scrollTo(
index: 50,
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
alignment: 0.5, // 居中
);