Flutter实现黄色与红色横向ListView同步滚动需求咨询
Flutter 横向ListView同步滚动实现方案
需求:当滚动黄色行或任意红色行的横向ListView时,所有红色行与黄色行的横向列表同步滚动。
实现思路
给每个横向ListView分配独立的ScrollController,通过监听所有控制器的滚动事件,同步所有列表的滚动偏移量,同时使用标志位避免循环触发监听逻辑。
完整实现代码
import 'package:flutter/material.dart'; class SyncHorizontalListView extends StatefulWidget { const SyncHorizontalListView({super.key}); @override State<SyncHorizontalListView> createState() => _SyncHorizontalListViewState(); } class _SyncHorizontalListViewState extends State<SyncHorizontalListView> { late ScrollController _yellowScrollController; final List<ScrollController> _redScrollControllers = []; bool _isSyncing = false; // 防止循环触发滚动监听 @override void initState() { super.initState(); // 初始化黄色区域的滚动控制器 _yellowScrollController = ScrollController(); _yellowScrollController.addListener(_syncScroll); // 初始化32个红色区域的滚动控制器并添加监听 for (int i = 0; i < 32; i++) { final controller = ScrollController(); _redScrollControllers.add(controller); controller.addListener(_syncScroll); } } // 同步所有横向列表的滚动位置 void _syncScroll() { if (_isSyncing) return; _isSyncing = true; // 获取当前正在滚动的列表的偏移量 double currentOffset = 0; // 先检查黄色列表是否在滚动 if (_yellowScrollController.hasClients && _yellowScrollController.position.isScrollingNotifier.value) { currentOffset = _yellowScrollController.offset; } else { // 遍历红色列表,找到正在滚动的那个 for (final controller in _redScrollControllers) { if (controller.hasClients && controller.position.isScrollingNotifier.value) { currentOffset = controller.offset; break; } } } // 同步黄色列表的位置 if (_yellowScrollController.hasClients && _yellowScrollController.offset != currentOffset) { _yellowScrollController.jumpTo(currentOffset); } // 同步所有红色列表的位置 for (final controller in _redScrollControllers) { if (controller.hasClients && controller.offset != currentOffset) { controller.jumpTo(currentOffset); } } _isSyncing = false; } @override void dispose() { // 释放所有控制器资源 _yellowScrollController.dispose(); for (final controller in _redScrollControllers) { controller.dispose(); } super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("同步横向列表"), ), body: LayoutBuilder( builder: (context, constraints) => Column( children: [ SizedBox( height: 40, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 2, child: Card( child: Container( width: 100, height: 30, color: Colors.green, child: const Text("固定标签栏")), ), ), Expanded( flex: 4, child: Padding( padding: const EdgeInsets.all(4.0), child: SizedBox( height: 30, child: ListView.builder( itemCount: 20, scrollDirection: Axis.horizontal, controller: _yellowScrollController, itemBuilder: (context, index) { return Container( width: 100, height: 30, color: Colors.yellow, child: Text("item $index"), ); }, ), ), )), ], ), ), Expanded( child: ListView( children: [ for (int i = 0; i < 32; i++) Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 2, child: Card( child: Container( width: 100, height: 30, color: Colors.blue, child: const Text("固定内容栏")), ), ), Expanded( flex: 4, child: Padding( padding: const EdgeInsets.all(4.0), child: SizedBox( height: 30, child: ListView.builder( itemCount: 20, scrollDirection: Axis.horizontal, controller: _redScrollControllers[i], itemBuilder: (context, index) { return Container( width: 100, height: 30, color: Colors.red, child: Text("item $index"), ); }, ), ), )), ], ), ], ), ), ], ), ), ); } }
UI效果截图

关键说明
- 控制器管理:为黄色列表和每个红色列表分别创建
ScrollController,统一管理并添加滚动监听。 - 同步逻辑:当任意列表滚动时,获取当前偏移量,调用
jumpTo方法同步其他所有列表的位置。 - 避免循环触发:使用
_isSyncing标志位,在同步过程中跳过监听回调,防止重复触发同步逻辑。
内容的提问来源于stack exchange,提问作者Akitha Iddamalgoda
相关产品推荐
相关产品推荐

