How do you add a Curves class animation to AnimationController in Flutter?

hello_friend picture hello_friend · Mar 26, 2019 · Viewed 7.8k times · Source

I'm trying to add the curves class animation 'Curves.bounceOut' to my code that uses an AnimationController.

Here is my code:

import 'package:flutter/material.dart';

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

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

class MyHomePage extends StatefulWidget {
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  var squareScale = 1.0;
  static AnimationController _controller;

  @override
  void initState() {
    _controller = AnimationController(
        vsync: this,
        lowerBound: 0.5,
        upperBound: 1.0,
        duration: Duration(milliseconds: 300));

    _controller.addListener(() {
      setState(() {
        squareScale = _controller.value;
      });
    });

    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Bounce Example"),
      ),
      body: Stack(
        children: <Widget>[
          Container(
            width: 150.0,
            height: 150.0,
            color: Colors.yellowAccent,
          ),
          Column(
            children: <Widget>[
              Row(
                children: <Widget>[
                  GestureDetector(
                    onTap: () {
                      _controller.forward(from: 0.0);
                    },
                    child: Transform.scale(
                      scale: squareScale,
                      child: Container(
                        width: 150.0,
                        height: 150.0,
                        color: Colors.green,
                      ),
                    ),
                  ),
                ],
              ),
            ],
          ),
        ],
      ),
    );
  }
}

Currently the green container animates from 0.5 scale to 1.0 scale but does not bounce. How can I add the 'Curves.bounceOut' animation so the container bounces when tapped?

Thanks in advance for any help!

Answer

R. Duggan picture R. Duggan · Mar 26, 2019

You'll want to use both an animation controller and a tween, which will allow you to add Curves.bounceOut.

Somewhere in your code add:

AnimationController _controller;
var scaleAnimation;

And in your initState() method:

_controller = new AnimationController(
 duration: new Duration(milliseconds: 300),
 vsync: this
)
..addListener(() {
  setState(() {});
});
scaleAnimation = new Tween(
  begin: 0.5,
  end: 1.0,
).animate(new CurvedAnimation(
  parent: _controller,
  curve: Curves.bounceOut
));

Note the ..addListener() is a nice bit of dart code that allows you to add a listener easily. The Tween is basically telling your animation that it needs to go from the value in begin to the value in end within the timeframe given in the AnimationController. To use this value in your code you can now just set the scale of your result of your animation:

child: Transform.scale(
  scale: scaleAnimation.value,
  child: Container(
    width: 150.0,
    height: 150.0,
    color: Colors.green,
  ),
),

And when the animation is called it will then automatically update the scale of the container.

Edit:

Change your widget to this:

child: isChanging ? Transform.scale(
  scale: scaleAnimation.value,
  child: Container(
    width: 150.0,
    height: 150.0,
    color: Colors.green,
  ),
) : Transform.scale(
  scale: 1.0,
  child: Container(
    width: 150.0,
    height: 150.0,
    color: Colors.green,
  ),
),

Keep your begin and end parameters as 0.5 and 1.0 respectively, but in your onTap() method before you forward your controller add:

onTap: () {
  setState(() {
    isChanging = true
  });
  _controller.forward(from: 0.0);
}

And anywhere in your code add the line bool isChanging. Finally you'll want to reset the shown widget at the end of your animation, so change your scaleAnimation to:

child: Transform.scale(
  scale: scaleAnimation.value,
  child: Container(
    width: 150.0,
    height: 150.0,
    color: Colors.green,
  ),
)..addStatusListener((AnimationStatus status) {
  if (status == AnimationStatus.completed) { //the animation is finished
    _controller.reset();
    setState(() {
      isChanging = false;
    }
  }
});