RiveAnimation.asset handles the basics. StateMachineController gives you the Hover and Clicked inputs for full interaction.
Open pubspec.yaml and add the dependency.
dependencies:
flutter:
sdk: flutter
rive: ^0.13.0Download your icon from Unicorn Icons. Put the .riv in an assets folder and declare it in pubspec.yaml.
flutter:
assets:
- assets/icons/your_icon.rivNo controller needed for a basic looping animation.
import 'package:rive/rive.dart';
class MyIcon extends StatelessWidget {
const MyIcon({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
width: 64,
height: 64,
child: RiveAnimation.asset(
'assets/icons/your_icon.riv',
stateMachines: const ['State Machine 1'],
fit: BoxFit.contain,
),
);
}
}Use StateMachineController to get the Hover and Clicked inputs. Wrap in MouseRegion and GestureDetector.
import 'package:flutter/material.dart';
import 'package:rive/rive.dart';
class InteractiveRiveIcon extends StatefulWidget {
const InteractiveRiveIcon({super.key});
@override
State<InteractiveRiveIcon> createState() => _InteractiveRiveIconState();
}
class _InteractiveRiveIconState extends State<InteractiveRiveIcon> {
StateMachineController? _controller;
SMIBool? _hoverInput;
SMITrigger? _clickInput;
void _onRiveInit(Artboard artboard) {
final controller = StateMachineController.fromArtboard(
artboard,
'State Machine 1',
);
if (controller != null) {
artboard.addController(controller);
_controller = controller;
_hoverInput = controller.findInput<bool>('Hover') as SMIBool?;
_clickInput = controller.findInput<bool>('Clicked') as SMITrigger?;
}
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: (_) => _hoverInput?.change(true),
onExit: (_) => _hoverInput?.change(false),
child: GestureDetector(
onTap: () => _clickInput?.fire(),
child: SizedBox(
width: 64,
height: 64,
child: RiveAnimation.asset(
'assets/icons/your_icon.riv',
onInit: _onRiveInit,
fit: BoxFit.contain,
),
),
),
);
}
}Fire inputs from outside the widget using a trigger or by toggling a boolean input.
// One-shot trigger
void triggerSuccess() {
final trigger = _controller?.findInput<bool>('Success') as SMITrigger?;
trigger?.fire();
}
// Boolean toggle
void setActive(bool value) {
final input = _controller?.findInput<bool>('IsActive') as SMIBool?;
input?.change(value);
}State machine input names
Every Unicorn Icon uses a state machine called State Machine 1 with boolean input Hover and trigger input Clicked.
Do I need StateMachineController for basic playback?
No. RiveAnimation.asset plays and loops automatically. Controller is only needed for interaction.
Rive or Lottie in Flutter?
Rive. GPU-accelerated, smaller files, state machines built in. Lottie is fine for simple looping animations with no interaction.
What inputs do Unicorn Icons include?
State machine State Machine 1 with Hover (SMIBool) and Clicked (SMITrigger).
Related guides
Get your animated icons
Browse icons ready for Flutter — free to download.