flutterflutter-animation

Rotating container indefinitely


I would like to rotate an Image indefinitely.

This container is one of the widget within the stack and would like this to be rotating continuously non stop.

final AnimationController animation = AnimationController(
  duration: const Duration(milliseconds: 1800),
  vsync: const NonStopVSync(),
)..repeat();

final Tween tween = Tween(begin: 0.0, end: math.pi);

var square = Container(
  width: 100,
  height: 100,
  transform: Matrix4.identity(),
  color: Colors.amber,
);

...

class Foo extends State<Bar> {
    ...


    animation.addListener((){
       square.transform = Matrix4.rotationZ(tween.evaluate(animation));
    });

    Widget build(BuildContext context) {
        return Stack(
           children: [
              ...
              Center(
                 child: square
              )
           ]
        )
    }
}

and I get this error: 'transform' can't be used as a setter because it's final. (assignment_to_final at [digital_clock] lib/digital_clock.dart:139)

How would I do what I'm trying to do?


Solution

  • Try something like this:

    class InfiniteAnimation extends StatefulWidget {
      final Widget child;
      final int durationInSeconds;
    
      InfiniteAnimation({@required this.child, this.durationInSeconds = 2,});
    
      @override
      _InfiniteAnimationState createState() => _InfiniteAnimationState();
    }
    
    class _InfiniteAnimationState extends State<InfiniteAnimation>
        with SingleTickerProviderStateMixin {
      AnimationController animationController;
      Animation<double> animation;
    ​
      @override
      void initState() {
        super.initState();
        animationController = AnimationController(
          vsync: this,
          duration: Duration(seconds: widget.durationInSeconds),
        );
        animation = Tween<double>(
          begin: 0,
          end: 12.5664, // 2Radians (360 degrees)
        ).animate(animationController);
    ​
        animationController.forward();
    ​
        animation.addStatusListener((status) {
          if (status == AnimationStatus.completed) {
            animationController.repeat();
          }
        });
      }
    ​
      @override
      Widget build(BuildContext context) {
        return AnimatedBuilder(
          animation: animationController,
          builder: (context, child) => Transform.rotate(
            angle: animation.value,
            child: widget.child,
          ),
        );
      }
    
      @override
      void dispose() {
        animationController?.dispose();
    
        super.dispose();
      }
    }
    

    You basically need to create a StatefulWidget that mixes in (with keyword) the SingleTickerProviderStateMixin, provide an AnimationController, start the animation, then when the animation completes, repeat.

    The AnimationBuilder is a better way of telling the widget to update on every frame without having to listen to the animationController and call setState explicitly.

    You can use it like this:

    InfiniteAnimation(
      durationInSeconds: 2, // this is the default value
      child: Icon(
        Icons.expand_more,
        size: 50.0,
        color: Colors.white,
      ),
    )