Flutter带Rive动画的底部导航栏仅热重载后正常工作,存在点击错位及无响应问题
Flutter带Rive动画的底部导航栏仅热重载后正常工作,存在点击错位及无响应问题
看起来你遇到了一个挺闹心的Rive导航栏问题——点击错位就算了,还只有热重载后才正常,重启又打回原形,这种状态不一致的情况确实让人头疼。我帮你分析下问题根源,再给你具体的解决办法:
问题核心原因
- 索引映射混乱:你用了
visibleIndices过滤导航项(根据inSession状态显示不同项),但点击事件里直接用了过滤后的索引去操作riveIconInputs(它是按原始全量导航项顺序初始化的),导致点击的可见项索引和Rive输入的索引不匹配,自然出现错位。 - Rive输入初始化不完整:
riveOnInit是在导航项的Rive组件build时才触发的,如果某个项一开始不可见(比如inSession为false时的通知、Profile),它的Rive组件不会被build,对应的输入就不会被添加到riveIconInputs里,点击时自然没反应;而热重载会强制重新build所有组件,这些输入才被补上,所以热重载后暂时正常。
具体解决步骤
1. 修正索引映射逻辑
在BottomNavBar的点击回调里,把可见项的索引转换成对应的原始导航项索引,再传给animateTheIcon:
比如在BottomNavBar的每个导航项的onTap里:
onTap: () { // 用visibleIndices把可见项索引转成原始索引 widget.animateTheIcon(widget.visibleIndices[index]); }
这样点击第0个可见项(比如Dashboard),就会传递它的原始索引(假设是2),对应riveIconInputs里正确的输入,不会再错位。
2. 预加载所有Rive输入,避免初始化不全
把Rive控制器和输入的初始化移到initState里,提前预加载所有导航项的资源,不管它是否可见:
@override void initState() { super.initState(); fabAnimationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 300), ); visibleLabels = List.filled(fabActions.length, false); // 预加载所有导航项的Rive控制器和输入 for (int i = 0; i < bottomNavItems.length; i++) { final navItem = bottomNavItems[i]; // 假设bottomNavItems里存了每个项的Rive资源路径和状态机名称 rootBundle.load(navItem['assetPath']).then((data) { final riveFile = RiveFile.import(data); final artboard = riveFile.mainArtboard; riveOnInit(artboard, stateMachineName: navItem['stateMachine'], index: i); }); } }
这样不管导航项是否一开始可见,对应的Rive输入都会被提前初始化到riveIconInputs里,再也不会出现点击无响应的情况。
3. 确保selectedNavIndex始终对应可见项
你已经在build开头加了这段逻辑,要保留它,确保当inSession状态变化时,选中的索引始终在可见范围内:
if (!visibleIndices.contains(selectedNavIndex)) { selectedNavIndex = visibleIndices.first; }
额外检查点
- 确认
riveOnInit里的逻辑:当riveIconInputs.length > index时直接返回,这个没问题,但预加载后每个索引都会被正确初始化,不会跳过。 - 检查
animateTheIcon里的索引判断:if (riveIconInputs.length > index),预加载后这个条件始终为true,点击任何项都会触发动画。
按照这些步骤调整后,应该就能解决点击错位、Profile无响应,以及只有热重载才正常的问题了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

