如何阻止Flutter Hero组件在特定路由间执行过渡动画?
Flutter Hero组件:指定路由间禁用过渡动画的解决方案
问题说明
给Hero组件设置相同tag后能实现路由切换的过渡动画,但现在需要让特定Hero tag在指定路由间跳过动画,能不能用你给出的HeroControllerScope示例代码实现?还有其他解决方案吗?
核心方案:使用HeroControllerScope+自定义HeroController
你给出的方法完全可行,这是Flutter官方支持的方式,只需要注意几个细节:
HeroController的excludedRoutes参数会直接排除指定路由,只要路由切换涉及到列表里的路由,当前HeroControllerScope包裹的Hero就不会播放动画。- 必须保证
Routes.BOOKING_SUMMARY这类路由名称和你在MaterialApp/CupertinoApp中注册的路由名完全一致,大小写、拼写都不能错,否则规则不会生效。
优化后的代码示例:
HeroControllerScope( // 传入自定义Hero控制器,指定要排除的路由 controller: HeroController( excludedRoutes: [ Routes.BOOKING_SUMMARY, Routes.SUPER_PRODUCTS, ], ), child: Hero( tag: 'unique-hero-tag', // 确保目标路由的Hero用同一个tag child: Image.network('https://i.picsum.photos/id/184/200/300.jpg'), ), )
进阶方案:精细控制特定路由跳转对
如果需要更精准的控制(比如仅在A路由跳转到B路由时禁用动画,其他跳转正常播放),可以自定义HeroController重写动画创建逻辑:
class CustomHeroController extends HeroController { // 存储需要阻止的路由对,格式如"路由A->路由B" final Set<String> blockedRoutePairs; CustomHeroController(this.blockedRoutePairs); @override Animation<double> createAnimation({ required Animation<double> parent, required HeroFlightDirection flightDirection, required BuildContext fromHeroContext, required BuildContext toHeroContext, }) { // 获取跳转前后的路由名称 final fromRouteName = ModalRoute.of(fromHeroContext)?.settings.name; final toRouteName = ModalRoute.of(toHeroContext)?.settings.name; // 检查是否是需要阻止的路由对(双向都要判断) final isBlocked = blockedRoutePairs.contains('$fromRouteName->$toRouteName') || blockedRoutePairs.contains('$toRouteName->$fromRouteName'); // 如果是阻止的路由对,直接返回完成状态的动画(无过渡) if (isBlocked) { return const AlwaysStoppedAnimation(1.0); } // 否则使用默认的Hero动画逻辑 return super.createAnimation( parent: parent, flightDirection: flightDirection, fromHeroContext: fromHeroContext, toHeroContext: toHeroContext, ); } } // 使用示例 HeroControllerScope( controller: CustomHeroController({ '${Routes.HOME}->${Routes.BOOKING_SUMMARY}', '${Routes.SUPER_PRODUCTS}->${Routes.DETAIL_PAGE}', }), child: Hero( tag: 'unique-hero-tag', child: Image.network('https://i.picsum.photos/id/184/200/300.jpg'), ), )
注意事项
- 每个需要单独控制的Hero组件都要套自己的
HeroControllerScope,这样控制器只会作用于当前Hero,不会影响页面上其他Hero的动画。 - 如果想全局禁用某些路由的Hero动画,可以直接在
MaterialApp的heroController参数中设置全局的HeroController,这样所有Hero组件都会遵循这个规则。
内容的提问来源于stack exchange,提问作者Ataberk
相关产品推荐
相关产品推荐

