|
|
@@ -139,18 +139,11 @@ class _StaggeredAutoScrollListViewState extends State<StaggeredAutoScrollListVie
|
|
|
@override
|
|
|
void initState() {
|
|
|
super.initState();
|
|
|
-
|
|
|
- // 初始化每一行的滚动控制器
|
|
|
for (int i = 0; i < rowCount; i++) {
|
|
|
- final controller = ScrollController();
|
|
|
- _controllers.add(controller);
|
|
|
+ _controllers.add(ScrollController());
|
|
|
}
|
|
|
-
|
|
|
- // 如果启用自动滚动,则在渲染后启动滚动逻辑
|
|
|
if (widget.isAutoScrolling) {
|
|
|
- WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
- _startAllScrolls();
|
|
|
- });
|
|
|
+ WidgetsBinding.instance.addPostFrameCallback((_) => _startAllScrolls());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -173,9 +166,7 @@ class _StaggeredAutoScrollListViewState extends State<StaggeredAutoScrollListVie
|
|
|
void _startAllScrolls() {
|
|
|
for (int i = 0; i < rowCount; i++) {
|
|
|
final controller = _controllers[i];
|
|
|
-
|
|
|
- // 每 50ms 滚动一次,实现平滑向右滚动效果
|
|
|
- final timer = Timer.periodic(const Duration(milliseconds: 50), (_) {
|
|
|
+ _timers.add(Timer.periodic(const Duration(milliseconds: 50), (_) {
|
|
|
if (!controller.hasClients) return;
|
|
|
|
|
|
final maxExtent = controller.position.maxScrollExtent;
|
|
|
@@ -183,39 +174,39 @@ class _StaggeredAutoScrollListViewState extends State<StaggeredAutoScrollListVie
|
|
|
final next = current + 1;
|
|
|
|
|
|
if (next >= maxExtent) {
|
|
|
- // 若滚动到底部,则跳转到中间,避免突然回到顶部产生视觉跳变
|
|
|
- controller.jumpTo(maxExtent / 2);
|
|
|
+ final viewportWidth = controller.position.viewportDimension;
|
|
|
+ final contentWidth = maxExtent + viewportWidth;
|
|
|
+ final originalContentWidth = contentWidth / loopFactor;
|
|
|
+ final offset = next - maxExtent;
|
|
|
+ controller.jumpTo(originalContentWidth + offset);
|
|
|
} else {
|
|
|
controller.jumpTo(next);
|
|
|
}
|
|
|
- });
|
|
|
-
|
|
|
- _timers.add(timer);
|
|
|
+ }));
|
|
|
}
|
|
|
}
|
|
|
+ @override
|
|
|
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
- // 每一行应显示的实际数据项数(取整向上)
|
|
|
final actualItemsPerRow = (widget.itemCount / rowCount).ceil();
|
|
|
-
|
|
|
- // 每一行扩展后的 item 数量(用于循环滚动)
|
|
|
- final extendedItemsPerRow = actualItemsPerRow * loopFactor;
|
|
|
-
|
|
|
return Column(
|
|
|
children: List.generate(rowCount, (rowIndex) {
|
|
|
+ final startIndex = rowIndex * actualItemsPerRow;
|
|
|
+ final endIndex = (startIndex + actualItemsPerRow).clamp(0, widget.itemCount);
|
|
|
+ final rowItems = List.generate(endIndex - startIndex, (i) => startIndex + i);
|
|
|
+ final extendedItems = List.generate(
|
|
|
+ rowItems.length * loopFactor,
|
|
|
+ (i) => rowItems[i % rowItems.length],
|
|
|
+ );
|
|
|
return SizedBox(
|
|
|
- height: 50.w, // 每行高度,单位为屏幕适配宽度
|
|
|
+ height: 50.w,
|
|
|
child: ListView.builder(
|
|
|
- controller: _controllers[rowIndex], // 设置对应行的滚动控制器
|
|
|
+ controller: _controllers[rowIndex],
|
|
|
scrollDirection: Axis.horizontal,
|
|
|
padding: widget.padding,
|
|
|
- itemCount: extendedItemsPerRow, // 扩展后的数量,制造无限滚动感
|
|
|
- itemBuilder: (context, index) {
|
|
|
- // 计算实际要展示的数据项索引
|
|
|
- final itemIndex = (rowIndex * actualItemsPerRow + index) % widget.itemCount;
|
|
|
- return widget.itemBuilder(context, itemIndex);
|
|
|
- },
|
|
|
+ itemCount: extendedItems.length,
|
|
|
+ itemBuilder: (context, index) => widget.itemBuilder(context, extendedItems[index]),
|
|
|
),
|
|
|
);
|
|
|
}),
|