Flutter 如何为Dialog实现的图片查看器添加上下滑动退出功能
上下滑动拖拽退出图片查看器Dialog实现方案
完整实现代码如下:
// 弹窗调用逻辑 showGeneralDialog( context: context, barrierColor: Colors.grey.shade900.withOpacity(0.95), barrierDismissible: false, barrierLabel: 'Dialog', transitionDuration: const Duration(milliseconds: 400), pageBuilder: (_, __, ___) { return const DragDismissViewer(); }, ); // 支持拖拽退出的自定义图片查看器组件 class DragDismissViewer extends StatefulWidget { const DragDismissViewer({super.key}); @override State<DragDismissViewer> createState() => _DragDismissViewerState(); } class _DragDismissViewerState extends State<DragDismissViewer> with SingleTickerProviderStateMixin { // 垂直拖拽偏移量 double _verticalOffset = 0; // 背景透明度 double _bgOpacity = 0.95; // 内容缩放比例 double _scale = 1.0; // 复位动画控制器 late AnimationController _resetController; // 拖拽阈值,偏移量绝对值超过该值则退出弹窗 final double _dismissThreshold = 120; @override void initState() { super.initState(); _resetController = AnimationController( vsync: this, duration: const Duration(milliseconds: 200), ); // 监听动画值更新,复位所有交互参数 _resetController.addListener(() { setState(() { _verticalOffset = _verticalOffset * (1 - _resetController.value); _bgOpacity = 0.95 - (0.95 - _bgOpacity) * _resetController.value; _scale = 1.0 - (1.0 - _scale) * _resetController.value; }); }); } @override void dispose() { _resetController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return GestureDetector( // 监听垂直拖拽更新事件 onVerticalDragUpdate: (details) { setState(() { _verticalOffset += details.delta.dy; // 根据偏移量动态计算背景透明度,偏移越大透明度越低 _bgOpacity = 0.95 - (_verticalOffset.abs() / 500).clamp(0, 0.95); // 根据偏移量动态计算内容缩放比例,偏移越大缩放越小 _scale = 1.0 - (_verticalOffset.abs() / 1000).clamp(0, 0.3); }); }, // 监听拖拽结束事件 onVerticalDragEnd: (details) { if (_verticalOffset.abs() > _dismissThreshold) { // 偏移超过阈值,直接退出弹窗 Navigator.of(context).pop(); } else { // 未超过阈值,启动动画复位到初始状态 _resetController.forward(from: 0); } }, child: SafeArea( child: Container( color: Colors.grey.shade900.withOpacity(_bgOpacity), child: Transform( transform: Matrix4.translationValues(0, _verticalOffset, 0) ..scale(_scale), alignment: Alignment.center, child: SizedBox.expand( child: Column( children: const [ // 此处替换为你自己的图片查看器内容即可 Expanded(child: Center(child: Text('图片查看器内容'))) ], ), ), ), ), ), ); } }
你可以根据自己的交互需求调整参数:
- 如果你只需要向下滑动退出,不需要向上触发,可以在
onVerticalDragUpdate里增加判断if(details.delta.dy > 0)再更新偏移量 _dismissThreshold数值越大需要滑动的距离越长,可以自行调整适配产品交互规范- 透明度、缩放的计算系数可以自行修改,调整拖拽过程中的视觉变化幅度
效果示意图:
内容的提问来源于stack exchange,提问作者Ali Abbas
相关产品推荐
相关产品推荐

