rive-app / rive-flutter

Flutter runtime for Rive
https://rive.app
MIT License
1.21k stars 191 forks source link

How do I change between animation names? #26

Closed do4Mother closed 3 years ago

do4Mother commented 3 years ago

I have 2 animations with the name "active" and "inactive", each of which is a one shot animation. How do I switch between animations?

Thanks

mjohnsullivan commented 3 years ago

Hi there!

While the SimpleAnimation controller is really intended for playing an animation either once or in a loop, you can use it to play different animations on-demand by adding and removing controllers from the artboard. Adding a SimpleAnimation will start that animation immediately, and if you want to replay it, simply remove and re-add the animation.

If you want more flexibility, the recommendation would be to create a custom controller to handle how you want different animations to play and mix together.

Here's a simple example that triggers two animations on button press:

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  SimpleAnimation _animation1, _animation2;

  void _playAnimation1() {
    // Remove the controller if necessary
    _riveArtboard.removeController(_animation1);
    // Add the controller to fire the animation
    _riveArtboard.addController(_animation1);
  }

  void _playAnimation2() {
    _riveArtboard.removeController(_animation2);
    _riveArtboard.addController(_animation2);
  }

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

    rootBundle.load('assets/loader.riv').then(
      (data) async {
        final file = RiveFile();

        if (file.import(data)) {
          final artboard = file.mainArtboard;

          // Create controllers for the one-shot animations you want to
          // repeatedly fire
          _animation1 = SimpleAnimation('load');
          _animation2 = SimpleAnimation('end');

          // Initially show the animation in its idle state
          artboard.addController(SimpleAnimation('idle'));

          setState(() => _riveArtboard = artboard);
        }
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(children: [
        Expanded(
          child: _riveArtboard == null
              ? const SizedBox()
              : Rive(artboard: _riveArtboard),
        ),
        Padding(
          padding: const EdgeInsets.symmetric(vertical: 10),
          child: FlatButton(
            child: Text('Play Animation 1'),
            onPressed: _playAnimation1,
          ),
        ),
        Padding(
          padding: const EdgeInsets.symmetric(vertical: 10),
          child: FlatButton(
            child: Text('Play Animation 2'),
            onPressed: _playAnimation2,
          ),
        ),
      ]),
    );
  }
}
do4Mother commented 3 years ago

Thank you so much for your help. after I tried it, I encountered a problem where the message icon did not work according to the animation design I had made. where the expected result will produce the following

ezgif-4-cf45e300d5d0

where the animation results that I made like this

ezgif-4-f90c4c78c15e

mjohnsullivan commented 3 years ago

Can you post some code that demonstrates the problem? Happy to take a look and help with it.

do4Mother commented 3 years ago

Can you post some code that demonstrates the problem? Happy to take a look and help with it.

yes, you can try this https://github.com/do4Mother/demo_navigation

thanks

mjohnsullivan commented 3 years ago

I had a look at the code and it appears fine. The problem is the way the animations are accumulating. When the inactive animation is run, the yellow spots are shrunk and disappear, via the group, shapes and paths. These changes are accumulated and not reset by the active animation, so they end up stuck in that state. By setting keyframes on the values changed by inactive in the active animation, the yellow spots can be shown again.

I've edited your animation file to make the changes; the one attached should now work for you. Let me know if this works!

chat.riv.zip

Here's a link to more info on how values accumulate in Rive: https://github.com/2d-inc/Flare-Flutter/issues/31#issuecomment-453640836 (this is for the older version of Rive, but holds true for this version).

do4Mother commented 3 years ago

Thank you so much, the chat icon works well!

vontdeux commented 2 years ago

is there an updated version of this in 2022? the code line final file = RiveFile(); produces below error :- The class 'RiveFile' doesn't have an unnamed constructor. Try using one of the named constructors defined in 'RiveFile'.

and the line if (file.import(data)) { produces below error :- The method 'import' isn't defined for the type 'RiveFile'. Try correcting the name to the name of an existing method, or defining a method named 'import'.