You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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官方推荐的交互动画实现方式:

  1. 确保你的Rive文件中创建了状态机,并添加了名为active的触发器输入(可在Rive编辑器中确认)。
  2. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 17:11:11