Atamyrat Babayev
Atamyrat Babayev

Reputation: 905

How to use rive's state machine in flutter?

I've created a .riv file with 3 state animations: start, processing, end, which are in "State machine". Rive team recently announced a new feature with dinamically changing animations, it's "State machine". Not sure, how to use it in flutter project, i.e how to dynamically change value of animation. If somebody needs some code, no problem, I could provide. Moreover, link to rive's "state machine" https://www.youtube.com/watch?v=0ihqZANziCk. I didn't find any examples related to this new feature. Please help! Thanks.

Upvotes: 9

Views: 6879

Answers (3)

Syed Mahfuzur Rahman
Syed Mahfuzur Rahman

Reputation: 477

If you are having SMIInput in your Animation them follow this code below:

import 'package:flutter/material.dart';
import 'package:rive/rive.dart';

class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});

@override
State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
SMIInput<double>? _input;
StateMachineController? controller;
double val = 0;

void _onRiveInit(Artboard artboard) {
 controller =
    StateMachineController.fromArtboard(artboard, 'State Machine 1');
artboard.addController(controller!);

_input = controller?.findInput<double>('input') as SMINumber;
_input?.change(val);
}

@override
Widget build(BuildContext context) {
return Scaffold(
    appBar: AppBar(
      title: const Text('Simple Animation'),
    ),
    body: Center(
      child: SizedBox(
        width: 200.0,
        child: GestureDetector(
          child: RiveAnimation.asset(
            'assets/rive/loading_state.riv',
            fit: BoxFit.fitWidth,
            onInit: (art) {
              _onRiveInit(art);
            },
          ),
          onTap: () {
            val++;
            _input?.change(val);
          },
        ),
      ),
    ));
  }
}

Upvotes: 2

J.K.
J.K.

Reputation: 303

The other answer is outdated.

class SimpleStateMachine extends StatefulWidget {
  const SimpleStateMachine({Key? key}) : super(key: key);

  @override
  _SimpleStateMachineState createState() => _SimpleStateMachineState();
}

class _SimpleStateMachineState extends State<SimpleStateMachine> {
  SMITrigger? _bump;

  void _onRiveInit(Artboard artboard) {
    final controller = StateMachineController.fromArtboard(artboard, 'bumpy');
    artboard.addController(controller!);
    _bump = controller.findInput<bool>('bump') as SMITrigger;
  }

  void _hitBump() => _bump?.fire();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Simple Animation'),
      ),
      body: Center(
        child: GestureDetector(
          child: RiveAnimation.network(
            'https://cdn.rive.app/animations/vehicles.riv',
            fit: BoxFit.cover,
            onInit: _onRiveInit,
          ),
          onTap: _hitBump,
        ),
      ),
    );
  }
}

See the RIVE guide:

https://help.rive.app/runtimes/state-machines

Upvotes: 8

Nicolas Morawietz
Nicolas Morawietz

Reputation: 108

There are examples on rives pub package site. Here is one for state machine. example_state_machine.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:rive/rive.dart';

/// An example showing how to drive two boolean state machine inputs.
class ExampleStateMachine extends StatefulWidget {
  const ExampleStateMachine({Key? key}) : super(key: key);

  @override
  _ExampleStateMachineState createState() => _ExampleStateMachineState();
}

class _ExampleStateMachineState extends State<ExampleStateMachine> {
  /// Tracks if the animation is playing by whether controller is running.
  bool get isPlaying => _controller?.isActive ?? false;

  Artboard? _riveArtboard;
  StateMachineController? _controller;
  SMIInput<bool>? _hoverInput;
  SMIInput<bool>? _pressInput;

  @override
  void initState() {
    super.initState();

    // Load the animation file from the bundle, note that you could also
    // download this. The RiveFile just expects a list of bytes.
    rootBundle.load('assets/rocket.riv').then(
      (data) async {
        // Load the RiveFile from the binary data.
        final file = RiveFile.import(data);

        // The artboard is the root of the animation and gets drawn in the
        // Rive widget.
        final artboard = file.mainArtboard;
        var controller =
            StateMachineController.fromArtboard(artboard, 'Button');
        if (controller != null) {
          artboard.addController(controller);
          _hoverInput = controller.findInput('Hover');
          _pressInput = controller.findInput('Press');
        }
        setState(() => _riveArtboard = artboard);
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey,
      appBar: AppBar(
        title: const Text('Button State Machine'),
      ),
      body: Center(
        child: _riveArtboard == null
            ? const SizedBox()
            : MouseRegion(
                onEnter: (_) => _hoverInput?.value = true,
                onExit: (_) => _hoverInput?.value = false,
                child: GestureDetector(
                  onTapDown: (_) => _pressInput?.value = true,
                  onTapCancel: () => _pressInput?.value = false,
                  onTapUp: (_) => _pressInput?.value = false,
                  child: SizedBox(
                    width: 250,
                    height: 250,
                    child: Rive(
                      artboard: _riveArtboard!,
                    ),
                  ),
                ),
              ),
      ),
    );
  }
}

Upvotes: 7

Related Questions