rive-flutter
rive-flutter copied to clipboard
[BUG] Rive StateMatchine with multiple layers does not work properly
Description
I have a Rive StateMachine with 3 layers in it. When an input is fired I have different conditions that trigger animations on all 3 of the layers.
It works perfectly with Rive for React, but when I import and use the Rive animation in flutter it only triggers the animation from the last layer and then exits, without animating the rest at the same time. Subsequent triggers also does not seem to trigger any animations.
Steps To Reproduce
Use the animation from the attached archive.
var ctrl = StateMachineController.fromArtboard(art, 'DivisionMachine',
onStateChange: (
String stateMachineName,
String stateName,
) {
print(stateMachineName);
print(stateName);
}) as StateMachineController;
art.addController(ctrl);
final divisionInput = ctrl.findInput<double>('division');
if (divisionInput != null) {
divisionInput.value = 7;
}
final suitInput = ctrl.findInput<double>('rank');
if (suitInput != null) {
suitInput.value = 3;
}
SMITrigger promote = ctrl.findSMI('promote');
SMITrigger demote = ctrl.findSMI('demote');
SMITrigger toClub = ctrl.findSMI('toClub');
SMITrigger toDiamond = ctrl.findSMI('toDiamond');
SMITrigger toHeart = ctrl.findSMI('toHeart');
SMITrigger toSpade = ctrl.findSMI('toSpade');
promote.fire();
toHeart.fire();
Source .riv
/.rev
file
Expected behavior
When I hit the trigger all layers of animations are executed simultaneously.
Device & Versions (please complete the following information)
- Device: iOS simulator
- Flutter Version: Channel stable, 3.13.0
@luigi-rosso any chance you can look into this, please? Thanks 🙏
Hi @Sh1d0w, I don't think I'm reproducing the problem correctly. This seems to behave properly for how the layers are setup:
https://github.com/rive-app/rive-flutter/assets/454182/089f634e-f2ca-4315-b1db-c6b520a886f6
Does that look as expected or is something missing that I'm not catching?
Code I used:
import 'package:flutter/material.dart';
import 'package:rive/rive.dart';
class SimpleStateMachine extends StatefulWidget {
const SimpleStateMachine({Key? key}) : super(key: key);
@override
State<SimpleStateMachine> createState() => _SimpleStateMachineState();
}
class _SimpleStateMachineState extends State<SimpleStateMachine> {
SMITrigger? _promote;
SMITrigger? _heart;
void _onRiveInit(Artboard artboard) {
final controller =
StateMachineController.fromArtboard(artboard, 'DivisionMachine');
artboard.addController(controller!);
_promote = controller.findInput<bool>('promote') as SMITrigger;
_heart = controller.findInput<bool>('toHeart') as SMITrigger;
final divisionInput = controller.findInput<double>('division');
if (divisionInput != null) {
divisionInput.value = 7;
}
final suitInput = controller.findInput<double>('rank');
if (suitInput != null) {
suitInput.value = 3;
}
}
void _onTap() {
_promote?.fire();
_heart?.fire();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Simple State Machine'),
),
body: Stack(
children: [
Center(
child: GestureDetector(
onTap: _onTap,
child: RiveAnimation.asset(
'assets/rank_change.riv',
fit: BoxFit.cover,
onInit: _onRiveInit,
),
),
),
],
),
);
}
}
@luigi-rosso Thanks for looking into this. Yes that's the correct behaviour. But in my app it does not do this with the latest version of the plugin. It skips the whole layer of background change, and only triggers the stars animation.
https://github.com/rive-app/rive-flutter/assets/5074917/692a0190-1674-4f27-821c-c75b6e893fe2
Weird. Let me setup a bare flutter repo and I will try to reproduce it there, as our app is closed source.
Thanks again for your time, will get back to you. 🙏
@luigi-rosso OK I've found out what the issue is. From the difference in your code and mine it seems that it works when it is triggered from onTap event, all good.
But if I do it like my original post, e.g. in the rive's onInit callback, it does not work.
Is that expected, a limitation, or a bug? As I would expect to setup and trigger the animation right inside the init, not via gesture? What would be the correct way to do that in such case?
The use case is as you can see I have a very complex animation, so I have some Flutter logic which trigger should be fired, so auto play does not suit my need. I need to setup the input first and then based on some conditions to trigger the correct animation right after the initialisation without user interference.
I've workaround it by creating an async function _animate that I call from onInit
and before the triggers I put this
await Future.delayed(Duration(milliseconds: 100));
It works, but not sure if this is intended or not. Feel free to close if you don't think this is bug. Thanks for your help mate!
Closing this but please reopen if needed.