3
votes

I have a .riv file created with Rive 2. It contains multiple animations.

I want to play a default animation but change it depending on an input from a stream.

The below code only plays the 'default' animation and isn't updating even if the switch case changes. The code jumps into the right switch case statement, I checked that with logging. But the animation isn't changing.

How can I play a different animation from the Rive artboard?

The State Class:

class _GraphicState extends State<Graphic> {
  final riveFileName = 'assets/rive/character.riv';
  Artboard _artboard;

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

  // loads a Rive file
  void _loadRiveFile() async {
    final bytes = await rootBundle.load(riveFileName);
    final file = RiveFile();

    if (file.import(bytes)) {
      // Select an animation by its name
      setState(() => _artboard = file.mainArtboard
        ..addController(
          SimpleAnimation('default'),
        ));
    }
  }

The build function:

@override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: widget.gameStageBloc.hangingParts,
        builder: (BuildContext ctx, AsyncSnapshot<int> status) {
          return Container(
            width: 350.0,
            height: 350.0,
            child: Align(
              alignment: Alignment.topCenter,
              child: Container(
                width: 350.0,
                height: 350.0,
                child: selectGraphic(status),
              ),
            ),
          );
        });
  }

The custom function to return the correct animation:

Widget selectGraphic(state) {
    if (_artboard != null) {
      switch (state) {
        case 1:
          _artboard.artboard..addController(SimpleAnimation('run'));
          break;
        case 2:
          _artboard.artboard..addController(SimpleAnimation('stand'));
          break;
        case 3:
          _artboard.artboard..addController(SimpleAnimation('dead'));
          break;
        default:
          _artboard.artboard..addController(SimpleAnimation('default'));
      }
      return Rive(
        artboard: _artboard,
        fit: BoxFit.cover,
      );
    } else {
      return Container();
    }
  }
2

2 Answers

0
votes

Try to call setState(() => {}) every time you do _artboard.artboard..addController

0
votes

Well, you can use 'Mixing Rive animations' reference

Code:

AnimationController animationController;
final String animationSell  = "sell_item";
final String animationAdd   = "add_item";
final String animationEmpty = "empty_cart";
final riveFileName          = 'assets/animation/cart.riv';
Artboard _artboard;
RiveAnimationController _wipersController;

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

void _loadRiveFile() async {
    final bytes = await rootBundle.load(riveFileName);
    final file = rive.RiveFile();
    if (file.import(bytes)) {
      setState(() => _artboard = file.mainArtboard..addController(rive.SimpleAnimation(animationSell)));
    }
}

void _wipersChange(KartState state) {
    switch (state.index) {
      case 0:
        _artboard.addController(
          _wipersController = rive.SimpleAnimation(animationEmpty),
        );
        break;
      case 1:
        _artboard.addController(
          _wipersController = rive.SimpleAnimation(animationAdd),
        );
        break;
      case 2:
        _artboard.addController(
          _wipersController = rive.SimpleAnimation(animationSell),
        );
        break;
      default:
        _artboard.addController(
          _wipersController = rive.SimpleAnimation(animationEmpty),
        );
    }
}

And put the widget anywhere

Container(
   height: 100.0, width: 100.0,
   child: Rive(
      artboard: _artboard,
      fit: BoxFit.scaleDown,
      alignment: Alignment.center,
   ),
)