Search code examples
flutteranimationcurve

AnimationController repeat with curve animation


How do I make a AnimatedController that repeats, but starts up with a curve animation.


Code:

AnimationController :

var _animating = false;

  AnimationController _rotationAnimationController;
  Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _rotationAnimationController = AnimationController(
      duration: Duration(milliseconds: 2000),
      vsync: this,
    );
    _animation =
        Tween<double>(begin: 0, end: 4 * pi ).animate(_rotationAnimationController)
      ..addListener(() {
        setState(() {});
      });
  }

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

Button :

GestureDetector(
                       onTap: () {
                         Duration startStopTime = Duration(seconds: 3);
                         if(_animating) {
                           _rotationAnimationController.animateBack(1, duration: startStopTime, curve: Curves.easeOut);
                           setState(() {});
                         } else {
                           _rotationAnimationController.repeat() //This needs to start with a curve
                         }
                         setState(() {
                           _animating = !_animating;
                         });
                       },
                       child: [...]
                     ),

If you could also make it so that when the repeat stops, it does that with a curve, that would be amazing too :)

Thanks for the help allready :D


Solution

  • The best I understood your question , you want a CurvedAnimation right ? This means your animation will repeat but follow a specific curve . So here the best I could do for you :

    Define your AnimationController like this :

     Animation<double> _animation;
     AnimationController _animationController;
    
    
      @override
      void initState() {
        super.initState();
    
        _animationController =
            AnimationController(vsync: this, duration: Duration(seconds: 2))
              ..addListener(() {
                setState(() {});
              });
    
        final Animation curve =
            CurvedAnimation(parent: _animationController, curve: Curves.easeOut);
    
        _animation = Tween<double>(begin: 0, end: pi * 4).animate(curve);
      }
    

    and your GestureDetector like this :

         GestureDetector(
                       onTap: () {
                            if (_animationController.isAnimating) 
      {
       _animationController.animateBack(0,duration: Duration(seconds: 2), curve: Curves.easeIn);
      } 
    
      else {
          _animationController.repeat();
        }
      },
                           child: [...]
                         ),
    

    Edit :

    I used a TweenAnimationBuilder to have the effect you want :

    import 'package:flutter/material.dart';
    import 'dart:math' as math;
    
    class TweenAnimatedBuilderRotate extends StatefulWidget {
      TweenAnimatedBuilderRotate({Key key}) : super(key: key);
    
      @override
      TweenAnimatedBuilderRotateState createState() =>
          TweenAnimatedBuilderRotateState();
    }
    
    class TweenAnimatedBuilderRotateState
        extends State<TweenAnimatedBuilderRotate> {
      double _newAngle = 0;
      Curve curveThatChanges = Curves.easeIn;
      bool isAnimating = false;
      int _millsecs = 2000;
      
    
      void onCompletion() {
        if (isAnimating) {
          _newAngle += 4 * math.pi;
          curveThatChanges = Curves.linear;
          _millsecs = 1000;
    
          setState(() {});
        } else {
          _newAngle = 0;
          _millsecs = 2000;
        }
      }
    
      void onContainerTap() {
        if (isAnimating) {
          isAnimating = false;
          _newAngle = _newAngle;
          setState(() {});
        } else {
          curveThatChanges = Curves.easeIn;
          _newAngle += 4 * math.pi;
          isAnimating = true;
          setState(() {});
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return TweenAnimationBuilder(
            tween: Tween<double>(begin: 0, end: _newAngle),
            duration: Duration(milliseconds: _millsecs),
            onEnd: () => onCompletion(),
            curve: curveThatChanges,
            builder: (
              BuildContext ctx,
              double angle,
              Widget child,
            ) {
              _newAngle = angle;
              return Center(
                child: Transform(
                  transform: Matrix4.identity()..rotateZ(_newAngle),
                  alignment: FractionalOffset.center,
                  child: GestureDetector(
                    child: Container(
                      color: Colors.blueGrey,
                      width: 200,
                      height: 200,
                    ),
                    onTap: () => onContainerTap(),
                  ),
                ),
              );
            });
      }
    }
    

    You can refer to this Medium article to understand about how TweenAnimationdBuilder Works. You can also modify _millsecs variable to speed up/down the animation. Pass TweenAnimatedBuilderRotate() in the body parameter of the Scaffold(...).