如何在SlidingUpPanel横向滚动时禁用纵向滚动
Flutter:实现横向滚动时禁用SlidingUpPanel纵向拖拽(复刻谷歌地图面板交互)
需求
复刻谷歌地图面板的交互逻辑:
- 面板默认支持纵向滑动调整位置
- 当用户操作面板内的横向滚动按钮栏时,立即禁用面板的纵向拖拽,避免同时滚动的糟糕体验
当前问题
使用sliding_up_panel组件时,横向滚动按钮栏的同时,面板仍能被纵向拖拽,交互体验差。
已尝试无效方案
- 使用
NotificationListener<ScrollNotification>检测横向滚动:仅能在滚动停止后生效,无法及时禁用纵向拖拽 - 使用
GestureDetector的onHorizontalDragDown/onHorizontalDragUpdate回调:未解决同时滚动问题
解决方案
核心思路是在横向拖拽手势触发的最早期,立即切换面板的拖拽状态,而非等待滚动事件触发。
1. 初始化面板控制器
通过SlidingUpPanelController直接控制面板是否允许拖拽:
late SlidingUpPanelController _panelController; @override void initState() { super.initState(); _panelController = SlidingUpPanelController(); }
2. 用GestureDetector拦截横向手势
将横向滚动按钮栏用GestureDetector包裹,在横向拖拽的生命周期事件中更新面板状态:
Widget _buildHorizontalButtonBar() { return GestureDetector( // 确保手势优先被当前组件拦截,不传递给父级面板 behavior: HitTestBehavior.opaque, // 开始横向拖拽时,禁用面板纵向拖拽 onHorizontalDragDown: (_) => _panelController.isDraggable = false, // 拖拽结束/取消时,恢复面板纵向拖拽 onHorizontalDragEnd: (_) => _panelController.isDraggable = true, onHorizontalDragCancel: () => _panelController.isDraggable = true, child: ListView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 16), children: const [ ElevatedButton(onPressed: null, child: Text("分类1")), SizedBox(width: 12), ElevatedButton(onPressed: null, child: Text("分类2")), SizedBox(width: 12), ElevatedButton(onPressed: null, child: Text("分类3")), // 更多按钮... ], ), ); }
3. 绑定控制器到SlidingUpPanel
将控制器传入面板,确保状态能实时生效:
@override Widget build(BuildContext context) { return Scaffold( body: SlidingUpPanel( controller: _panelController, minHeight: 120, maxHeight: MediaQuery.of(context).size.height * 0.75, panelBuilder: (scrollController) { return SingleChildScrollView( controller: scrollController, child: Column( children: [ const Padding( padding: EdgeInsets.all(16), child: Text("面板标题", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), ), // 插入横向按钮栏 _buildHorizontalButtonBar(), // 面板其他内容 const SizedBox(height: 600, child: Center(child: Text("面板内容区域"))), ], ), ); }, ), ); }
额外优化:双重保障滚动状态恢复
若担心快速滑动导致状态未及时恢复,可结合NotificationListener在滚动结束时强制恢复拖拽:
// 修改_buildHorizontalButtonBar中的ListView部分 child: NotificationListener<ScrollNotification>( onNotification: (notification) { if (notification is ScrollEndNotification) { _panelController.isDraggable = true; } return false; // 不阻止滚动事件传递 }, child: ListView(/* ... */), ),
内容的提问来源于stack exchange,提问作者eljorgit
相关产品推荐
相关产品推荐

