How to keep the state of rive animation in flutter

806 Views Asked by At

I have added a rive ❤️ heart animation to a iconButton in flutter. when I tap on it, it animates from Unlike > Like and when I tapped again it animates backwards. Which is perfectly working. But the thing is, when I close the page and reopen the same page, Rive animation animates again from the very beginning (the default state of the animation is outline bordered heart icon, which I have to tap on it to make ❤️ filled heart icon). So the problem is if I like an item, close the page and then reopened the page I have to tap on it again, in order to make the item favorite or not. I also created a isFavorite bool to tack the icon button state, the thing is I don't know how to sync the bool with rive animation.

So this is what I want: I need the riveAnimation to stay liked or unliked according to the state of isFavourite bool + Unlike, Dislike transition animation. This may be hard to understand. Please leave a comment what part is that you do not understand.

Rive Animation I Used (go to rive)

class Place with ChangeNotifier {
  bool isFavourite;

  Place(
      {this.isFavourite = false});

  void toggleFavouriteStatus() {
    isFavourite = !isFavourite;
    notifyListeners();
  }
}

. . . . . . .

  SMIInput<bool>? _heartButtonInput;
  Artboard? _heartButtonArtboard;


  @override
  void initState() {
    super.initState();
    rootBundle.load('assets/rive/heart.riv').then(
      (data) {
        final file = RiveFile.import(data);
        final artboard = file.mainArtboard;
        var controller = StateMachineController.fromArtboard(
          artboard,
          'state',
        );
        if (controller != null) {
          artboard.addController(controller);
          _heartButtonInput = controller.findInput('Like');
        }
        setState(() => _heartButtonArtboard = artboard);
      },
    );
  }

  @override
  Widget build(BuildContext context) {
final Fav = Provider.of<Place>(context); // I used provider package to retrieve bool data
    void _heartButtonAnimation() {
      if (_heartButtonInput?.value == false &&
          _heartButtonInput?.controller.isActive == false) {
        _heartButtonInput?.value = true;
      } else if (_heartButtonInput?.value == true &&
          _heartButtonInput?.controller.isActive == false) {
        _heartButtonInput?.value = false;
      }
    }

    return Stack(
      alignment: Alignment.bottomCenter,
      children: [
        Positioned(
          right: 8,
          top: 8,
          child: Container(
            child: Center(
              child: Material(
                color: Colors.transparent,
                child: _heartButtonArtboard == null
                    ? const SizedBox()
                    : IconButton(
                        onPressed: () {
                          Fav.toggleFavouriteStatus();
                          _heartButtonAnimation();  
                        },
                        icon: Rive(
                          artboard: _heartButtonArtboard!,
                          fit: BoxFit.cover,
                        ),
                      ),
              ),
            ),
          ),
        )
      ],
    );
  }
}
1

There are 1 best solutions below

0
On

I'm not sure if I understood correctly. When your record is already given a heart, then after revisiting it, you want the heart to be displayed in "liked" state without running animating it. Is that it?

If so, IMO the problem is within your state machine not allowing the animation to be started in the desired state of "liked". For the heart to get to the liked state, it needs to pass through the liking animation. This is how your state machine looks now:

enter image description here

You should define two paths from Entry state depending on the value of your Like input. Take a look at a state machine from a checkbox I've imported to Flutter lately. Each of the "idle" timelines have only one keyframe for being checked or unchecked. On entry, there's an intersection where a decision is made based on the initial value of checked input.

enter image description here

This way you can display your heart in the desired state without any animation happening when the widget is built.