1. 序章
在现代移动应用开发中,滑动视图是常见的交互模式之一。特别是当你需要展示大量内容时,使用自动滚动的滑动视图可以显著提升用户体验。在这篇文章中,我们将讨论如何使用 Flutter 实现一个自动滚动的列表视图。
2. 效果
3. 实现思路
为了实现一个自动滚动的列表视图,我们需要考虑以下几点:
- ScrollController 管理:每个横向列表需要一个
ScrollController
来管理其滚动状态。 - 自动滚动机制:使用
Timer
定时器定期触发滚动事件。 - 用户交互管理:通过手势检测来判断用户何时开始或结束手动滚动,并暂停或恢复自动滚动。
4. 实现代码
以下是实现这个功能的完整代码:
import 'dart:async';
import 'package:flutter/material.dart';
//https://github.com/yixiaolunhui/flutter_xy
class LoopScrollWidget extends StatefulWidget {
final List<List<dynamic>> items;
final double? rowHeight;
final Widget Function(BuildContext context, int rowIndex, int index) itemBuilder;
const LoopScrollWidget({
Key? key,
this.rowHeight = 50,
required this.items,
required this.itemBuilder,
}) : super(key: key);
LoopScrollWidgetState createState() => LoopScrollWidgetState();
}
class LoopScrollWidgetState extends State<LoopScrollWidget> {
late final List<ScrollController> _scrollControllers;
late final List<bool> _isScrollingList;
final double _scrollIncrement = 4.0;
final Duration _scrollDuration = const Duration(milliseconds: 50);
Timer? _scrollTimer;
void initState() {
super.initState();
_scrollControllers = List.generate(widget.items.length, (index) => ScrollController());
_isScrollingList = List.generate(widget.items.length, (index) => false);
WidgetsBinding.instance.addPostFrameCallback((_) {
_startAutoScroll();
});
}
void dispose() {
_scrollTimer?.cancel();
for (var controller in _scrollControllers) {
controller.dispose();
}
super.dispose();
}
Widget build(BuildContext context) {
return Column(
children: List.generate(widget.items.length, (rowIndex) {
return GestureDetector(
onPanDown: (_) => _isScrollingList[rowIndex] = true,
onPanEnd: (_) => _isScrollingList[rowIndex] = false,
onTapUp: (_) => _isScrollingList[rowIndex] = false,
child: NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification is ScrollEndNotification) {
_isScrollingList[rowIndex] = false;
}
return false;
},
child: SizedBox(
height: widget.rowHeight,
child: ListView.builder(
controller: _scrollControllers[rowIndex],
physics: const BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
final position = index % widget.items[rowIndex].length;
return Row(
children: [widget.itemBuilder(context, rowIndex, position)],
);
},
),
),
),
);
}),
);
}
void _startAutoScroll() {
_scrollTimer?.cancel();
_scrollTimer = Timer.periodic(_scrollDuration, (timer) {
for (var i = 0; i < _scrollControllers.length; i++) {
if (!_isScrollingList[i] && _scrollControllers[i].hasClients) {
_scrollControllers[i].animateTo(
_scrollControllers[i].offset + _scrollIncrement,
duration: _scrollDuration,
curve: Curves.linear,
);
}
}
});
}
}
详细解释
- Stateful Widget:
LoopScrollWidget
继承自StatefulWidget
,其状态管理由LoopScrollWidgetState
类负责。 - 初始化:在
initState
方法中,我们初始化了每个行的ScrollController
和一个布尔列表_isScrollingList
来跟踪哪些行正在被手动滚动。 - 自动滚动:使用
Timer.periodic
来定时滚动每一行,除非该行当前正在被手动滚动。 - 手势检测:使用
GestureDetector
来检测用户何时开始或结束手动滚动,并通过NotificationListener
来监听滚动结束通知。
详情:github.com/yixiaolunhui/flutter_xy