You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 12:24:06