Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chaining seperate animations that work on the same properties

I have looked at Staggered animations for chaining animations but there they use one animation for one widget's properties, e.g. a opacity animation is controlling the fade in, but what if I want to first fade in and then later fade out that same widget? I mean I already have created the fade in animation and that is used for the widget opacity value like this:

_opacityDontWorry = Tween(
  begin: 0.0,
  end: 1.0,
).animate(
  CurvedAnimation(parent: _animationController, curve: Interval(0.0, 0.75, curve: Curves.easeIn)),
);

so those two are now bound together like this:

Opacity(
  opacity: _opacityDontWorry.value,
  child: Text("Don't worry"),
)

This work just fine and my Opacity get faded in, but after it is faded in I would like it to fade out after a short pause, but how can I do this? Do I create a new Tween and overwrite the _opacityDontWorry with that, or? Am I even on the right path here, how do I chain multiple animations that alter the same properties on a widget?

Thank you
Søren

like image 405
Neigaard Avatar asked Jul 05 '19 10:07

Neigaard


2 Answers

May be this is a late answer. But a TweenSequence is the right class for animating the same attribute(s) mutations one after another. Docs reference.

like image 185
Denis Bakhtin Avatar answered Oct 06 '22 07:10

Denis Bakhtin


You can use addStatusListener on your Animation. Check when the animation is completed and then call reverse() on your AnimationController.

If you want to, you can call reverse() inside a Future.delayed() for making a pause.

I've made this example for you:

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
  AnimationController _animationController;
  Animation _opacityDontWorry;

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

    _animationController = AnimationController(duration: Duration(seconds: 1), vsync: this);
    _opacityDontWorry = Tween(
      begin: 0.0,
      end: 1.0,
    ).animate(
      CurvedAnimation(parent: _animationController, curve: Curves.easeIn),
    )..addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        Future.delayed(Duration(seconds: 3), () {
          _animationController.reverse();
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton.extended(
        label: Text('Animate'),
        onPressed: () => _animationController.forward(),
      ),
      body: Center(
        child: AnimatedBuilder(
          animation: _opacityDontWorry,
          builder: (context, widget) {
            return Opacity(
              opacity: _opacityDontWorry.value,
              child: Text("Don't worry"),
            );
          },
        ),
      ),
    );
  }
}

UPDATE

In case you need to play this animation, and call another one after that, you can extract the opacity value to a variable. Then update that value from as many consecutive animations as you need.

  _firstAnimation = Tween(
    begin: 0.0,
    end: 1.0,
  ).animate(
    CurvedAnimation(parent: _animationController, curve: Interval(0.0, 0.20, curve: Curves.easeIn)),
  )..addListener(() {
      setState(() => _opacity = _firstAnimation.value);
    });

  // Leave an interval pause if you need
  _secondAnimation = Tween(
    begin: 1.0,
    end: 0.0,
  ).animate(
    CurvedAnimation(parent: _animationController, curve: Interval(0.40, 0.60, curve: Curves.easeIn)),
  )..addListener(() {
      setState(() => _opacity = _secondAnimation.value);
    });

In your widget's opacity property, instead of using _firstAnimation.value use _opacity.

like image 20
GaboBrandX Avatar answered Oct 06 '22 08:10

GaboBrandX