Flutter Hero组件过渡时如何实现90度旋转并保持旋转状态
问题修正方案
你当前代码的核心问题有两处:
- 目标页
Hero的子组件外层已经包裹了RotatedBox(quarterTurns: 1),通过toHeroContext.widget获取到的toHero本身就是已经旋转90度的组件,再在flightShuttleBuilder中叠加旋转动画会导致角度计算错误。 - 没有适配
HeroFlightDirection的双向场景,执行页面返回(pop)动画时,旋转逻辑不会自动反向,会出现动画错乱。
正确实现步骤
- 源页面(跳转发起页)的
Hero子组件保持原始无旋转状态,不要额外包裹旋转组件 - 目标页面的
Hero子组件保留RotatedBox(quarterTurns: 1)作为静态终态,保证动画结束后组件保持90度旋转的展示效果 - 在
flightShuttleBuilder中根据飞行方向动态调整旋转值的区间,不要直接复用带旋转属性的toHero/fromHero作为动画子组件,而是提取公共的无旋转内容作为过渡子组件,避免角度叠加。
参考代码
源页面Hero代码
Hero( tag: 'america', // 源页保持无旋转状态 child: SizedBox( height: 100, width: 100, child: SvgPicture.asset('assets/icons/america.svg'), ), )
目标页面Hero代码
Hero( tag: 'america', flightShuttleBuilder: ( BuildContext flightContext, Animation<double> animation, HeroFlightDirection flightDirection, BuildContext fromHeroContext, BuildContext toHeroContext, ) { // 传入无旋转的公共子组件,避免和静态RotatedBox的角度叠加 final Widget commonChild = SizedBox( height: 100, width: 100, child: SvgPicture.asset('assets/icons/america.svg'), ); // 根据飞行方向匹配旋转区间 final Animatable<double> rotationTween = flightDirection == HeroFlightDirection.push ? Tween(begin: 0, end: 0.25) // 进入新页面时从0度平滑转到90度 : Tween(begin: 0.25, end: 0); // 返回上一页时从90度平滑转回0度 return RotationTransition( turns: animation.drive(rotationTween), child: commonChild, ); }, // 静态终态固定为90度旋转,和动画结束角度完全对齐无跳变 child: RotatedBox( quarterTurns: 1, child: SizedBox( height: 100, width: 100, child: SvgPicture.asset('assets/icons/america.svg'), ), ), )
优化提示
如果公共子组件逻辑比较复杂,可以把无旋转的子组件抽成独立的可复用Widget,在源页、目标页、flightShuttleBuilder中统一调用,减少冗余代码。
如果需要更自然的缓动效果,可以给动画加曲线配置,替代默认的线性动画:
final curvedAnimation = CurvedAnimation( parent: animation, curve: Curves.easeInOut, ); // 后续RotationTransition使用curvedAnimation驱动旋转值即可
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

