Flutter如何实现类Google Maps列表的Draggable scrollable sheet交互
Flutter实现类Google Maps拖拽唤出滚动面板方案
Flutter 原生自带的DraggableScrollableSheet组件无需引入第三方依赖,即可实现你要的交互:初始状态仅露出底部一小段容器,上滑拖拽任意位置(包括容器内的列表项)即可跟随手势展开面板,支持多档位吸附、和列表滚动自动联动,完全匹配Google Maps的交互逻辑。
效果参考
- 初始折叠状态:

- 上滑半展开状态:

- 完全展开状态:

核心实现代码
页面采用Stack层叠布局,底层放置地图/主内容区,顶层放置DraggableScrollableSheet即可,完整可运行示例:
import 'package:flutter/material.dart'; class GoogleMapStyleSheetPage extends StatelessWidget { const GoogleMapStyleSheetPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ // 底层主内容(这里替换成你的Google Maps/其他地图组件即可) Container(color: Colors.lightBlue[50], child: const Center(child: Text("地图区域"))), // 顶层拖拽面板 DraggableScrollableSheet( // 初始高度:仅露出底部12%高度的容器作为拖拽入口 initialChildSize: 0.12, // 最小折叠高度:和初始值一致 minChildSize: 0.12, // 最大展开高度:占屏幕90%,留顶部状态栏空间 maxChildSize: 0.9, // 开启档位吸附 snap: true, // 三个吸附档位:折叠、半开、全开 snapSizes: const [0.12, 0.5, 0.9], builder: (context, scrollController) { return Container( decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(16)), boxShadow: [BoxShadow(blurRadius: 12, color: Colors.black12)], ), child: Column( children: [ // 顶部拖拽把手 Container( margin: const EdgeInsets.symmetric(vertical: 12), width: 40, height: 4, decoration: BoxDecoration( color: Colors.grey[350], borderRadius: BorderRadius.circular(2), ), ), // 联动列表:必须传入builder提供的scrollController Expanded( child: ListView.builder( controller: scrollController, padding: EdgeInsets.zero, itemCount: 30, itemBuilder: (context, index) { return ListTile( leading: const Icon(Icons.location_on), title: Text("地点条目 ${index + 1}"), subtitle: Text("这是第${index + 1}个地点的描述信息"), ); }, ), ), ], ), ); }, ), ], ), ); } }
关键注意点
- 手势联动无需额外手写监听:只要你把列表组件的
controller属性赋值为DraggableScrollableSheet.builder回调提供的scrollController,组件会自动处理手势优先级:面板未完全展开时,垂直拖拽优先触发面板展开/折叠;面板完全展开后,垂直拖拽优先触发列表滚动,拖拽列表项时也能直接唤出面板,和Google Maps逻辑完全一致。 - 如需主动控制面板展开/折叠,可以通过GlobalKey获取组件状态调用动画方法:
// 声明key final sheetKey = GlobalKey<DraggableScrollableSheetState>(); // 绑定到DraggableScrollableSheet的key属性 // 主动展开到半开状态示例 sheetKey.currentState?.animateTo( 0.5, duration: const Duration(milliseconds: 300), curve: Curves.easeOutCubic, ); - 如果需要调整面板跟手度,可以修改组件的
snapAnimationDuration参数调整吸附动画时长,日常开发设200-300ms体验最佳。
内容的提问来源于stack exchange,提问作者Vivek Anand
相关产品推荐
相关产品推荐

