"How to use Rive's state machine in Flutter" is the most voted Rive question on Stack Overflow, and many answers online target the older API. Version 0.14 changed the package a lot, so check which version a tutorial uses.
Load and render
late final fileLoader = FileLoader.fromAsset(
'assets/toggle.riv',
riveFactory: Factory.rive,
);
@override
Widget build(BuildContext context) {
return RiveWidgetBuilder(
fileLoader: fileLoader,
builder: (context, state) => switch (state) {
RiveLoading() => const CircularProgressIndicator(),
RiveFailed() => Text(state.error.toString()),
RiveLoaded() => RiveWidget(controller: state.controller, fit: Fit.contain),
},
);
}Call fileLoader.dispose() in dispose(). Rive also suggests calling await RiveNative.init() early in main().
Pick a state machine
final controller = RiveWidgetController(
file,
artboardSelector: ArtboardSelector.byName('Main'),
stateMachineSelector: StateMachineSelector.byName('Toggle'),
);If you do not pass a selector, the default state machine is used. A common bug is a file whose default plays a plain animation instead of the state machine you built.
Drive it from Dart with data binding
final vmi = controller.dataBind(DataBind.auto());
final progress = vmi.number('Progress')!;
progress.value = 0.75;
progress.addListener((value) => debugPrint('$value'));Booleans, triggers, strings and colours work the same way through their own property types; see Rive's data binding docs for each. Ask your designer for the exact view model and property names, because lookups are by name.
ExodeUI works on the same idea, with inputs and events that your Flutter code controls, and stores the file as readable JSON. We make ExodeUI.