2

I'm trying to re-play a Flare animation in Flutter. Not loop the animation when it has complete. I want an animation to be played on demand, the same animation.

When I switch between animations it works fine when just swapping the string and calling setState. Is there a simple way to do this.

Here's what I'm currently doing.

class _FlareDemoState extends State<FlareDemo> {

  String animationToPlay = 'activate';

  @override
  Widget build(BuildContext context) {

    print('Animation to play: $animationToPlay');

    return Scaffold(
      backgroundColor: Colors.purple,
      body: GestureDetector(
        onTap: () {
          setState(() {

          });
        },
        child: FlareActor('assets/button-animation.flr',
            animation: animationToPlay)));
   }
}

My logs result when I tap the animation

I/flutter (18959): Animation to play: activate
I/flutter (18959): Animation to play: activate
I/chatty  (18959): uid=10088(com.example.flare_tutorial) Thread-2 identical 2 lines
I/flutter (18959): Animation to play: activate
I/flutter (18959): Animation to play: activate
I/chatty  (18959): uid=10088(com.example.flare_tutorial) Thread-2 identical 7 lines
I/flutter (18959): Animation to play: activate
I/flutter (18959): Animation to play: activate
Reloaded 2 of 495 libraries in 672ms.
I/flutter (18959): Animation to play: activate

Everything is called, it plays the first time, but after that the animation doesn't replay.

Filled Stacks
  • 4,116
  • 1
  • 23
  • 36

3 Answers3

6

A cleaner way to do this is using a custom FlareController. There's a concrete FlareControls implementation that fits this use case nicely.

class _MyHomePageState extends State<MyHomePage> {
  // Store a reference to some controls for the Flare widget
  final FlareControls controls = FlareControls();

  void _playSuccessAnimation() {
    // Use the controls to trigger an animation.
    controls.play("success");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: FlareActor("assets/Teddy.flr",
          animation: "idle",
          fit: BoxFit.contain,
          alignment: Alignment.center,
          // Make sure you use the controls with the Flare Actor widget.
          controller: controls),
      floatingActionButton: FloatingActionButton(
        onPressed: _playSuccessAnimation,
        tooltip: 'Play',
        child: Icon(Icons.play_arrow),
      ),
    );
  }
}

Note that this example also plays an idle background animation which loops. Any call to FlareControls.play will mix the incoming animation over this background idle animation. You simply omit the animation: "idle" argument if you don't want/need a background animation.

Full example here: https://github.com/luigi-rosso/flare_controls

Luigi Rosso
  • 111
  • 1
  • 2
1

Based on the answer from @Eugene I came up with a temporary solution. I set the value to empty, start a timer for 50ms and then set the value back to the animation I wanted to play again.

class _FlareDemoState extends State<FlareDemo> {

String animationToPlay = 'activate';

@override
Widget build(BuildContext context) {

print('Animation to play: $animationToPlay');

return Scaffold(
  backgroundColor: Colors.purple,
  body: GestureDetector(
    onTap: () {
      _setAnimationToPlay('activate');
    },
    child: FlareActor('assets/button-animation.flr',
        animation: animationToPlay)));
  }
}

void _setAnimationToPlay(String animation) {
  if (animation == _animationToPlay) {
    _animationToPlay = '';
    Timer(const Duration(milliseconds: 50), () {
      setState(() {
        _animationToPlay = animation;
      });
    });
  } else {
    _animationToPlay = animation;
  }
}

It's messy workaround but it gets the job done. Thank you @Eugene for planting the seed.

Filled Stacks
  • 4,116
  • 1
  • 23
  • 36
  • thumbs up for the use of timer. I wanted to stop playingg the animation after 1 ound. Timer helped. – Sisir Dec 19 '20 at 12:21
-1
 FlareActor(
                      "assets/animation/day_night.flr",
                      alignment: Alignment.center,
                      fit: BoxFit.cover,
                      animation: _animation,
                      callback: (string) {
                       if(string=="switch_night"){
                         setState(() {
                           _animation = _animationNight;

                         });
                       }else if(string=="switch_day"){
                         setState(() {
                           _animation = _animationDay;

                         });
                       }
                      },
                    )