Flutter骰子应用首次点击无Rive动画,后续正常问题求助
解决Flutter Rive骰子动画首次点击不触发问题
问题分析
首次点击按钮时动画无响应,第二次及之后正常,核心原因:
- 旧版
RiveFile.initialize()调用导致初始化延迟,状态机未完全就绪时触发动画无效; - 首次点击时骰子数值更新与动画触发的时序冲突,状态机未及时接收数值变化就触发了trigger。
解决方案
1. 移除废弃初始化代码
新版rive库已自动完成初始化,无需手动调用RiveFile.initialize(),删除该行可避免初始化流程异常。
2. 优化动画触发时序
通过addPostFrameCallback等待当前帧绘制完成后再触发动画,确保骰子数值已同步到Rive状态机。
3. 完善初始化状态控制
初始化时设置骰子默认值,同时给按钮添加状态判断,避免未就绪时的无效点击。
修改后的完整代码
import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:rive/rive.dart'; class Rolldice extends StatefulWidget { const Rolldice({super.key}); @override State<Rolldice> createState() => _RolldiceState(); } class _RolldiceState extends State<Rolldice> { Artboard? riveArtboard; var dicevalue = 1; // 初始化默认点数 SMINumber? diceNumber; SMITrigger? rollTrigger; bool isRolling = false; @override void initState() { _loadRiveFile(); super.initState(); } void _loadRiveFile() async { try { final data = await rootBundle.load("assets/images/shakeable_dice.riv"); final file = RiveFile.import(data); final artboard = file.mainArtboard; final controller = StateMachineController.fromArtboard(artboard, 'StateIdle'); if (controller != null) { artboard.addController(controller); diceNumber = controller.findSMI('Number'); rollTrigger = controller.findSMI('Trigger'); // 同步初始数值到状态机 if (diceNumber != null) { diceNumber!.value = dicevalue.toDouble(); } setState(() => riveArtboard = artboard); } } catch (e) { print("Error loading Rive file: $e"); } } void _triggerRoll() { if (isRolling) return; isRolling = true; final newDiceValue = Random().nextInt(6) + 1; setState(() { dicevalue = newDiceValue; }); diceNumber!.value = newDiceValue.toDouble(); // 等待帧绘制完成后触发动画,确保数值同步完成 WidgetsBinding.instance.addPostFrameCallback((_) { rollTrigger!.fire(); }); Future.delayed(const Duration(seconds: 1), () { setState(() { isRolling = false; }); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Roll Dice')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: riveArtboard == null ? const Center(child: Text("Loading...")) : Center(child: Rive(artboard: riveArtboard!)), ), const SizedBox(height: 20), Text( dicevalue.toString(), style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold), ), const SizedBox(height: 20), ElevatedButton( onPressed: (rollTrigger == null || isRolling) ? null : _triggerRoll, child: Text(isRolling ? "Rolling..." : "Roll"), ), ], ), ), ); } }
额外检查项
确保你的Rive文件状态机配置正确:
StateIdle状态机中,Trigger输入需正确关联「Idle → Rolling」的过渡条件;Number输入需绑定到骰子点数的显示逻辑,动画结束后会根据该数值切换到对应点数状态。
内容的提问来源于stack exchange,提问作者Yongsak Saengsuk
相关产品推荐
相关产品推荐

