Flutter中Rive按钮onTap动画异常问题排查与修复求助
Rive按钮动画二次点击无响应问题修复
问题原因
你使用的OneShotAnimation控制器是一次性动画控制器——它在完成单次动画播放后,会自动进入不可重新激活的状态。首次点击时动画正常执行是因为控制器处于初始可激活状态,但动画完成后,即使再次设置_controller.isActive = true,也无法触发动画,导致后续点击直接执行跳转逻辑。
修复方案
有两种可靠的修复方式,根据你的场景选择:
方案1:重置OneShotAnimation控制器
每次动画完成后重新初始化控制器,确保点击时控制器处于可激活状态:
class _MyHomePageState extends State<MyHomePage> { late RiveAnimationController _controller; @override void initState() { super.initState(); _initAnimationController(); } // 封装控制器初始化逻辑 void _initAnimationController() { _controller = OneShotAnimation( "active", autoplay: false, onStop: () { // 动画结束后自动重置控制器 setState(() { _controller.dispose(); _initAnimationController(); }); }, ); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( // 保留原有布局代码... child: GestureDetector( onTap: () { _controller.isActive = true; Future.delayed( const Duration(milliseconds: 750), () { Navigator.push( context, MaterialPageRoute(builder: (context) => const Test()), ); }, ); }, child: SizedBox( height: 64, width: MediaQuery.of(context).size.width, child: RiveAnimation.asset( "assets/RiveAssets/buttonT.riv", controllers: [_controller], ), ), ), // 保留原有布局代码... ); } }
方案2:使用StateMachineController(推荐)
如果你的Rive动画包含状态机(多数交互类按钮都会使用状态机),使用StateMachineController可以更灵活地重复触发动画,这是Rive官方推荐的交互动画实现方式:
- 确保你的Rive文件中创建了状态机,并添加了名为
active的触发器输入(可在Rive编辑器中确认)。 - 修改Flutter代码:
class _MyHomePageState extends State<MyHomePage> { StateMachineController? _stateMachineController; SMITrigger? _buttonTrigger; @override void dispose() { _stateMachineController?.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( // 保留原有布局代码... child: GestureDetector( onTap: () { _buttonTrigger?.fire(); // 触发状态机中的动画 Future.delayed( const Duration(milliseconds: 750), () { Navigator.push( context, MaterialPageRoute(builder: (context) => const Test()), ); }, ); }, child: SizedBox( height: 64, width: MediaQuery.of(context).size.width, child: RiveAnimation.asset( "assets/RiveAssets/buttonT.riv", onInit: (artboard) { // 初始化状态机控制器 _stateMachineController = StateMachineController.fromArtboard( artboard, "State Machine 1", // 替换为你Rive文件中的状态机名称 ); if (_stateMachineController != null) { artboard.addController(_stateMachineController!); // 获取触发器输入 _buttonTrigger = _stateMachineController?.findSMI("active"); } }, ), ), ), // 保留原有布局代码... ); } }
注意事项
- 若使用方案2,需确认Rive文件中的状态机名称和触发器名称与代码中一致(可在Rive编辑器的「State Machine」面板查看)。
- 避免使用
Future.delayed硬编码等待时间,更好的方式是监听动画完成事件后再执行跳转,比如在OneShotAnimation的onStop回调中触发导航,或者在状态机中添加动画完成的回调。
内容的提问来源于stack exchange,提问作者pgcreto
相关产品推荐
相关产品推荐

