0

I've created a Flare animation which is simply a subscribe/unsubscribe button in a Flutter application.

The animation runs when the button is pressed, and all appears fine, if the user is subscribed for instance, the button reads 'subscribed' after the user pushes it. But if the user is already subscribed and returns to a relevant screen the button is not in the subscribed state. It remains in the original 'subscribe' state

I am working with a single artboard in my Flare file. It has two animations, subscribe and unsubscribe which do what they sound like. The animations do play appropriately when clicking on the button, however the states aren't preserved when a screen is reloaded. For instance if I've subscribed, and and leave the app and come back, I see the 'subscribe' button even though i've already done so.

I'm unsure if I need to have 2 separate art boards for this or if there is a better way?

class SubUnsubButton extends StatefulWidget {
  final Fight fight;
  const SubUnsubButton({
    Key key,
    @required this.fight,
  }) : super(key: key);

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

class _SubUnsubButtonState extends State<SubUnsubButton>
    with TickerProviderStateMixin {
  FlareControls flareController = FlareControls();
  String animation;

  @override
  initState() {
    super.initState();
    widget.fight.userIsSubscribed ? animation = 'Sub' : animation = 'Unsub';
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          Container(
            height: 50,
            child: FlatButton(
              child: FlareActor(
                "assets/animations/FightBell.flr",
                artboard: "SubUnsub",
                controller: flareController,
                fit: BoxFit.contain,
                animation: animation,
                sizeFromArtboard: true,
              ),
              onPressed: () {
                // If not subsribed
                FirebaseUser user = Provider.of<FirebaseUser>(context);
                if (!widget.fight.userIsSubscribed) {
                    animation = 'Sub';
                } else {
                    animation = 'Unsub';

                }
              },
            ),
          ),
        ],
      ),
    );
  }
}
jonnyc
  • 177
  • 1
  • 5

2 Answers2

0

You shouldn't need a second artboard. The easiest way to fix this is by adding an initState method and setting the animation value based on the same logic you have in the onPressed callback. Note that the change to the animation value in onPressed should really be done in a setState call to ensure the widget is updated when the animation value changes.

A generally cleaner way to do this is using a boolean value like isSubscribed instead of encapsulating the isSubscribed logic into another (Fight) object. This will allow the flutter widget system to automatically call didUpdateWidget on your State class when isSubscribed changes. Then you can respond to that change by doing calling setState and changing the animation value. You'd probably pass in some other callback to be invoked when onPressed is called so that the widget using this SubUnsubButton can change the isSubscribed value.

You may not need a stateful widget at all, take a look at the checkbox example in the Flare-Flutter repository. It displays a list of checkboxes with randomly chosen values at boot for whether they are checked or not. The SmileySwitch checkbox class is implemented as a stateless widget while the implementing Settings class just iterates through the values, creates a SmileySwitch for each, and then responds to the onToggle callback by changing the value as necessary. This should be pretty similar to what you are trying to do.

Luigi Rosso
  • 111
  • 1
  • 2
  • Hey Luigi, thanks for the detailed answer. I've followed most of your advice. My only issue now is that whenever the screen is loaded, the state of the button is correctly shown but Flare runs the animation from one state to another which I don't want. For example, if the user is subscribed, when the page is loaded, I see the animation play from 'unsubscribed' to 'subscribed'. How can I avoid this? I'd only like the animation to run when the user actually presses the button. – jonnyc Oct 28 '19 at 14:05
  • Got this figured out. Sorry I missed the information in the first pass of your post. All I had to do was switch the snapToEnd property to true in the init method, and then switch it back to false before changing the animations after s subscribe/unsubscribe. – jonnyc Oct 31 '19 at 15:28
0

As Luigi demonstrated in his linked example, the snapToEnd flare actor property was all that was needed to fix the issue. Set it as true when first rendering the animation to the correct state. Then switch it to false when you get user input that should cause the animation to run.

class SubUnsubButton extends StatefulWidget {
  final Fight fight;
  const SubUnsubButton({
    Key key,
    @required this.fight,
  }) : super(key: key);

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

class _SubUnsubButtonState extends State<SubUnsubButton>
    with TickerProviderStateMixin {
  FlareControls flareController = FlareControls();
  String animation;
  bool _snapToEnd

  @override
  initState() {
    super.initState();
    _snapToEnd = true
    widget.fight.userIsSubscribed ? animation = 'Sub' : animation = 'Unsub';
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          Container(
            height: 50,
            child: FlatButton(
              child: FlareActor(
                "assets/animations/FightBell.flr",
                artboard: "SubUnsub",
                controller: flareController,
                fit: BoxFit.contain,
                animation: animation,
                sizeFromArtboard: true,
              ),
              onPressed: () {
                // If not subsribed
                FirebaseUser user = Provider.of<FirebaseUser>(context);
                if (!widget.fight.userIsSubscribed) {
                    setState(() {
                      _snapToEnd = false;
                      animation = 'Sub';
                    });
                } else {
                    setState(() {
                      _snapToEnd = false;
                      animation = 'Unsub';
                    })

                }
              },
            ),
          ),
        ],
      ),
    );
  }
}
jonnyc
  • 177
  • 1
  • 5