Flutter中如何通过拖动容器实现逐步滑动导航到新页面的效果
实现方案
你需要实现的这个上滑拖拽跳转交互,不用直接调用原生Navigator.push,可以先在当前页面的Stack层叠加NewPage做跟随动画,动画完成后再执行跳转补全路由栈,避免路由栈逻辑混乱。
第一步:新增状态变量
在_MainPageState中定义以下变量:
// 设备屏幕高度 double _screenHeight = 0; // 拖拽偏移量,向上拖拽时为负值 double _dragOffset = 0; // 控制是否展示拖拽态的NewPage bool _isShowDragPage = false; // 跳转触发阈值,拖拽超过屏幕30%高度就触发跳转 final double _dragThreshold = 0.3; // 补间动画控制器 late AnimationController _animationController;
第二步:初始化与销毁逻辑
在生命周期方法中完成变量的初始化和回收:
@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { _screenHeight = MediaQuery.of(context).size.height; }); _animationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 200)); } @override void dispose() { _animationController.dispose(); super.dispose(); }
第三步:修改Stack布局,叠加NewPage层
调整你现有代码的Stack结构,补充手势回调和NewPage的跟随逻辑:
Stack( children: [ // 原有主页面的其他内容 ... // 原有可拖拽Container的逻辑改造 Positioned( // 原有top值加上拖拽偏移量,实现Container跟随手势移动 top: _yourOriginalTop + _dragOffset, child: GestureDetector( onVerticalDragStart: (details) { // 拖拽开始,标记展示NewPage层 setState(() { _isShowDragPage = true; }); }, onVerticalDragUpdate: (details) { // 仅响应向上拖拽的手势 if (details.delta.dy < 0) { setState(() { _dragOffset += details.delta.dy; }); } }, onVerticalDragEnd: (details) async { // 计算当前拖拽距离占屏幕的比例 double dragProportion = _dragOffset.abs() / _screenHeight; if (dragProportion >= _dragThreshold) { // 超过阈值,执行动画让NewPage铺满全屏 _animationController.forward(); setState(() { _dragOffset = -_screenHeight; }); // 动画结束后执行正式路由跳转 await Future.delayed(const Duration(milliseconds: 200)); if (mounted) { // 关闭路由默认跳转动画,避免和自定义动画冲突 Navigator.push(context, PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => const NewPage(), transitionDuration: Duration.zero, )); // 重置状态 setState(() { _isShowDragPage = false; _dragOffset = 0; }); } } else { // 未超过阈值,回弹复位 setState(() { _dragOffset = 0; _isShowDragPage = false; }); } }, child: Container(/* 原有Container的配置 */), ), ), // 叠加在顶层的NewPage,仅拖拽状态下展示 if (_isShowDragPage) Positioned( top: _screenHeight + _dragOffset, left: 0, right: 0, height: _screenHeight, // 可添加Opacity实现NewPage随拖拽进度渐显的效果 child: Opacity( opacity: (_dragOffset.abs() / (_screenHeight * _dragThreshold)).clamp(0, 1), child: const NewPage(), ), ) ], )
内容的提问来源于stack exchange,提问作者mms59
相关产品推荐
相关产品推荐

