如何在WidgetsApp中实现先淡出旧页面再淡入新页面的路由过渡?
实现旧页面淡出后新页面淡入的路由过渡
嘿,我完全懂你的需求——现在的淡入过渡里旧页面一直杵着,想要先让旧页面彻底消失,再让新页面平滑出现对吧?其实你找对方向了,secondaryAnimation就是用来处理旧页面过渡的核心,但得搞清楚它的动画逻辑,再结合isInitialRoute优化初始路由的情况,就能完美解决问题。
问题根源
你之前嵌套FadeTransition用secondaryAnimation时页面快速消失,是因为在push新路由时,secondaryAnimation的取值是从1.0降到0.0,直接把它作为旧页面的opacity的话,旧页面会瞬间变透明。我们需要把这个动画的方向和执行时机调整一下,让旧页面先完成淡出,再启动新页面的淡入。
适配WidgetsApp的完整解决方案
这里给你写好可直接用的代码,同时利用isInitialRoute避免初始路由的多余渲染:
return PageRouteBuilder( opaque: false, // 核心!必须设为false,否则旧页面会被新页面完全遮挡 transitionDuration: const Duration(milliseconds: 800), // 可自定义总过渡时长 reverseTransitionDuration: const Duration(milliseconds: 800), // 保证返回时过渡一致 pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) { // 旧页面淡出动画:把secondaryAnimation的[1→0]反转,并用Interval控制在前半段执行 final oldPageFade = Tween<double>(begin: 1.0, end: 0.0).animate( CurvedAnimation( parent: secondaryAnimation, curve: const Interval(0.0, 0.5), // 前50%时间完成旧页面淡出 ), ); // 新页面淡入动画:用Interval控制在后半段执行 final newPageFade = Tween<double>(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: animation, curve: const Interval(0.5, 1.0), // 后50%时间完成新页面淡入 ), ); return Stack( children: [ // 只有非初始路由时才渲染旧页面,避免初始加载时的空布局 if (!isInitialRoute) FadeTransition( opacity: oldPageFade, child: ModalRoute.of(context)!.child, // 通过context获取当前旧页面 ), // 新页面的淡入效果 FadeTransition( opacity: newPageFade, child: route, ), ], ); }, );
关键细节解释
opaque: false:这个设置是基础,它允许新页面透明,让下方的旧页面能显示出来完成淡出动画。- 动画区间拆分:用
Interval把总过渡时间切成两段,确保旧页面完全消失后,新页面才开始淡入,完美实现你要的顺序效果。 isInitialRoute的作用:当是应用的第一个路由时,没有旧页面需要处理,通过这个判断可以避免渲染多余的空组件,优化初始加载的性能和体验。- 反向过渡适配:设置
reverseTransitionDuration是为了在pop返回时,新页面先淡出,旧页面再淡入,保持整个路由切换的交互一致性。
自定义调整建议
你可以根据自己的视觉需求修改参数:
- 调整
transitionDuration来改变整个过渡的快慢 - 修改
Interval的区间值,比如把旧页面的区间设为0.0, 0.6,新页面设为0.6, 1.0,让旧页面淡出的时间更长一点
内容的提问来源于stack exchange,提问作者Ilja
相关产品推荐
相关产品推荐

