How to rotate an image using Flutter AnimationController and Transform?
Asked Answered
S

11

54

I have star png image and I need to rotate the star using Flutter AnimationController and Transformer. I couldn't find any documents or example for image rotation animation.

Any idea How to rotate an image using Flutter AnimationController and Transform?

UPDATE:

class _MyHomePageState extends State<MyHomePage>  with TickerProviderStateMixin {

  AnimationController animationController;

  @override
  void initState() {
    super.initState();
    animationController = new AnimationController(
      vsync: this,
      duration: new Duration(milliseconds: 5000),
    );
    animationController.forward();
    animationController.addListener(() {
      setState(() {
        if (animationController.status == AnimationStatus.completed) {
          animationController.repeat();
        }
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Container(
      alignment: Alignment.center,
      color: Colors.white,
      child: new AnimatedBuilder(
        animation: animationController,
        child: new Container(
          height: 80.0,
          width: 80.0,
          child: new Image.asset('images/StarLogo.png'),
        ),
        builder: (BuildContext context, Widget _widget) {
          return new Transform.rotate(
            angle: animationController.value,
            child: _widget,
          );
        },
      ),
    );
  }
}
Stiver answered 12/12, 2018 at 14:47 Comment(3)
Could you past code with initialization of animationRotate?Pentachlorophenol
I update my code. Problem is that it never rotate 360 degree. It rotates about 200 or something and starts over and there is a gap they I can see it that it redraws. Having an issue to rotate 360 degree and and when stops I need to repeat without delay so I can get continues rotation whiteout stop...Stiver
Updated the answerPentachlorophenol
P
43

Here my example of rotating image. I don't know - but maybe it suits for you

AnimationController rotationController;

@override
void initState() {
  rotationController = AnimationController(duration: const Duration(milliseconds: 500), vsync: this);
  super.initState();
}
//...
RotationTransition(
  turns: Tween(begin: 0.0, end: 1.0).animate(rotationController),
  child: ImgButton(...)
//...
rotationController.forward(from: 0.0); // it starts the animation

UPD - how to solve problem with Transform.rotate

In your case all works exactly as you've written - it rotates image from 0.0 to 1.0 (it's default parameters for AnimationController). For full circle you have to set upper parameter to 2 * pi (from math package)

import 'dart:math';
//...
animationController = AnimationController(vsync: this, duration: Duration(seconds: 5), upperBound: pi * 2);
Pentachlorophenol answered 12/12, 2018 at 14:55 Comment(2)
how can we add curves hereConfectionery
@Confectionery here is answer https://mcmap.net/q/339617/-how-do-you-add-a-curves-class-animation-to-animationcontroller-in-flutterPentachlorophenol
P
67

Full example (null safe):

Demo Screenshot

Press "go" makes the star icon spin until you press "stop".

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 {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    _controller = AnimationController(
      duration: const Duration(milliseconds: 5000),
      vsync: this,
    );
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Demo"),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            RotationTransition(
              turns: Tween(begin: 0.0, end: 1.0).animate(_controller),
              child: Icon(Icons.stars),
            ),
            ElevatedButton(
              child: Text("go"),
              onPressed: () => _controller.forward(),
            ),
            ElevatedButton(
              child: Text("reset"),
              onPressed: () => _controller.reset(),
            ),
          ],
        ),
      ),
    );
  }
}

Step by step guide:

First, let your widget state class implement SingleTickerProviderStateMixin.

Secondly, define an AnimationController and don't forget to dispose it. If you are not yet using null-safe, remove the late keyword.

late AnimationController _controller;

@override
void initState() {
  _controller = AnimationController(
    duration: const Duration(milliseconds: 5000),
    vsync: this,
  );
  super.initState();
}

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

Then wrap your Widget with RotationTransition.

RotationTransition(
  turns: Tween(begin: 0.0, end: 1.0).animate(_controller),
  child: Icon(Icons.stars),
),

Finally, call methods on the AnimationController to start/stop animation.

  • Run the animation once, use .forward
  • Loop the animation, use .repeat
  • Stop immediately, use .stop
  • Stop and set it back to original rotation, use .reset
  • Stop and animate to a rotation value, use .animateTo
Piggyback answered 26/3, 2019 at 17:49 Comment(1)
Thanks so much for this answer. I just wanted to add that if you want to add some nice animations on your rotation you could use this: CurveTween(curve: Curves.elasticInOut).animate(_controller) and you can experiment with the effects by changing Curves.elasticInOutQuartern
O
52

Screenshot (Null Safe)

enter image description here


Full code:

import 'dart:math' as math;

class _FooPageState extends State<FooPage> with SingleTickerProviderStateMixin{
  late final AnimationController _controller = AnimationController(vsync: this, duration: Duration(seconds: 2))..repeat();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: AnimatedBuilder(
          animation: _controller,
          builder: (_, child) {
            return Transform.rotate(
              angle: _controller.value * 2 * math.pi,
              child: child,
            );
          },
          child: FlutterLogo(size: 200),
        ),
      ),
    );
  }
}
Old answered 15/5, 2020 at 12:25 Comment(3)
How to rotate this along the Y axis, any ideas?Nympha
Hi, you've forgot to dispose the animation controller, which leads to 'ticker leak' exception each time the widget is disposed. Let me edit your solution...Adore
@DmytroGierman To keep the answer small and relevant, I didn't dispose the controller.Old
P
43

Here my example of rotating image. I don't know - but maybe it suits for you

AnimationController rotationController;

@override
void initState() {
  rotationController = AnimationController(duration: const Duration(milliseconds: 500), vsync: this);
  super.initState();
}
//...
RotationTransition(
  turns: Tween(begin: 0.0, end: 1.0).animate(rotationController),
  child: ImgButton(...)
//...
rotationController.forward(from: 0.0); // it starts the animation

UPD - how to solve problem with Transform.rotate

In your case all works exactly as you've written - it rotates image from 0.0 to 1.0 (it's default parameters for AnimationController). For full circle you have to set upper parameter to 2 * pi (from math package)

import 'dart:math';
//...
animationController = AnimationController(vsync: this, duration: Duration(seconds: 5), upperBound: pi * 2);
Pentachlorophenol answered 12/12, 2018 at 14:55 Comment(2)
how can we add curves hereConfectionery
@Confectionery here is answer https://mcmap.net/q/339617/-how-do-you-add-a-curves-class-animation-to-animationcontroller-in-flutterPentachlorophenol
R
4

Here i rotate 3 images at once... images saved in assets folder... if you want you can use network images also... i am here rotate 3 images on 3 speeds...

import 'package:flutter/material.dart';
import 'package:fynd/services/auth.dart';
import 'dart:async';
import 'package:fynd/services/cons.dart';

class SplashScreen extends StatefulWidget {
  _SplashScreen createState() => new _SplashScreen();
}

class _SplashScreen extends State<StatefulWidget>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;

  @override
  void initState() {
    super.initState();
    animationController = new AnimationController(
      vsync: this,
      duration: new Duration(seconds: 5),
    );

    animationController.repeat();
  }

  @override
  Widget build(BuildContext context) {

    return new Container(
      alignment: Alignment.center,
      color: Colors.white,
      child: new AnimatedBuilder(
        animation: animationController,
        child: new Container(
          decoration: BoxDecoration(
              image: DecorationImage(
                  image: AssetImage('assets/images/splash_circle3.png'))),
          child: new AnimatedBuilder(
            animation: animationController,
            child: new Container(
              decoration: BoxDecoration(
                  image: DecorationImage(
                      image: AssetImage('assets/images/splash_circle2.png'))),
              child: new AnimatedBuilder(
                  animation: animationController,
                  child: Container(
                      child: Container(
                    decoration: BoxDecoration(
                        image: DecorationImage(
                            image: AssetImage(
                                'assets/images/splash_circle1.png'))),
                  )),
                  builder: (BuildContext context, Widget _widget) {
                    return new Transform.rotate(
                      angle: animationController.value * 4,
                      child: _widget,
                    );
                  }),
            ),
            builder: (BuildContext context, Widget _widget) {
              return new Transform.rotate(
                angle: animationController.value * 5,
                child: _widget,
              );
            },
          ),
        ),
        builder: (BuildContext context, Widget _widget) {
          return new Transform.rotate(
            angle: animationController.value * 6,
            child: _widget,
          );
        },
      ),
    );
  }
}
Rawdon answered 8/5, 2019 at 5:12 Comment(0)
R
4

here i put the animated builder in Stack. then you can animate image rotate right(clockwise) and rotate left(anti clockwise).

import 'package:flutter/material.dart';
import 'package:fynd/services/auth.dart';
import 'dart:async';
import 'package:fynd/services/cons.dart';

class SplashScreen extends StatefulWidget {
  _SplashScreen createState() => new _SplashScreen();
}

class _SplashScreen extends State<StatefulWidget>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;

  @override
  void initState() {
    super.initState();
    animationController = new AnimationController(
      vsync: this,
      duration: new Duration(seconds: 5),
    );

    animationController.repeat();

  }

  @override
  Widget build(BuildContext context)

    return new Container(
      alignment: Alignment.center,
      color: Colors.white,

      child: new Stack(children: <Widget>[

        new AnimatedBuilder(
          animation: animationController,
          child :Container(
            decoration: BoxDecoration(
                image: DecorationImage(image: AssetImage('assets/images/splash_circle3.png'),fit: BoxFit.cover)),

          ),
          builder: (BuildContext context, Widget _widget) {
            return new Transform.rotate(
              angle: animationController.value * 10,
              child: _widget,
            );
          },
        ),

       new AnimatedBuilder(
        animation: animationController,
        child: Container(
          decoration: BoxDecoration(
              image: DecorationImage(image: AssetImage('assets/images/splash_circle2.png'),fit: BoxFit.cover)),

        ),
        builder: (BuildContext context, Widget _widget) {
          return new Transform.rotate(
            angle: -animationController.value * 10,
            child: _widget,
          );
        },
       ),

        new AnimatedBuilder(
            animation: animationController,
           child: Container(
              decoration: BoxDecoration(
                  image: DecorationImage(image: AssetImage('assets/images/splash_circle1.png'), fit: BoxFit.cover)),
            ),
            builder: (BuildContext context, Widget _widget) {
              return new Transform.rotate(
                angle: animationController.value * 10,
                child: _widget,
              );
            }),

      ],),
    );
  }
}
Rawdon answered 8/5, 2019 at 8:44 Comment(0)
D
3

Flutter also has the widget AnimatedRotation (docs) which makes rotating something much easier.

You only need a double to set the state of the rotation. It works in a percentage of rotation, if you turn it into degrees, it will be 0.0 = 0deg, 1.0 = 360deg

double turns = 0.0;
AnimatedRotation(
  duration: const Duration(milliseconds: 500),
  turns: turns,
  child: const Icon(Icons.refresh),
)

To make the rotation happen you only need to update the state, and Flutter will execute the animation automatically

void _changeRotation() {
  setState(() => turns += 1.0 / 8.0);
}

Full example taken from the Flutter docs to rotate the flutter Logo

class LogoRotate extends StatefulWidget {
  const LogoRotate({Key? key}) : super(key: key);

  @override
  State<LogoRotate> createState() => LogoRotateState();
}

class LogoRotateState extends State<LogoRotate> {
  double turns = 0.0;

  void _changeRotation() {
    setState(() => turns += 1.0 / 8.0);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        ElevatedButton(
          onPressed: _changeRotation,
          child: const Text('Rotate Logo'),
        ),
        Padding(
          padding: const EdgeInsets.all(50),
          child: AnimatedRotation(
            turns: turns,
            duration: const Duration(seconds: 1),
            child: const FlutterLogo(),
          ),
        ),
      ],
    );
  }
}
Dudden answered 27/5, 2022 at 17:37 Comment(0)
D
2
class _MyHomePageState extends State<MyHomePage>  with TickerProviderStateMixin {

  AnimationController animationController;

  @override
  void initState() {
    super.initState();
    animationController = new AnimationController(
      vsync: this,
      duration: new Duration(milliseconds: 5000),
    );
    animationController.repeat();

  }

  @override
  Widget build(BuildContext context) {
    return new Container(
      alignment: Alignment.center,
      color: Colors.white,
      child: RotationTransition(
              child: Icon(Icons.refresh),
              turns: controller,
            )
    );
  }
}
Disorganization answered 19/11, 2020 at 15:52 Comment(0)
D
1

    _controller = AnimationController(duration: const Duration(seconds: 3), vsync: this);
    _animation = Tween(begin: 0.0, end: 250.0).animate(_controller)
      ..addListener(() {
        setState(() {});
      })
      ..addStatusListener((state) {
        if (state == AnimationStatus.completed) {
          print("complete");
        }
      });
    _controller.forward();

    new Future.delayed(
        const Duration(seconds: 5),
            () => Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => SignScreen()),
        ));    
Drawknife answered 25/10, 2020 at 22:57 Comment(0)
O
0

full example just call ImageAnimateRotate( your widget )

class ImageAnimateRotate extends StatefulWidget {
  final Widget child;
  const ImageAnimateRotate({Key? key, required this.child}) : super(key: key);

  @override
  _ImageAnimateRotateState createState() => _ImageAnimateRotateState();
}

class _ImageAnimateRotateState extends State<ImageAnimateRotate> with SingleTickerProviderStateMixin {
  late final AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: Duration(seconds: 20))..repeat();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: AnimatedBuilder(
        animation: _controller,
        builder: (_, child) {
          return Transform.rotate(
            angle: _controller.value * 2 * math.pi,
            child: child,
          );
        },
        child: widget.child,
      ),
    );
  }
}
Offing answered 15/9, 2021 at 11:32 Comment(0)
C
0
IconButton(
        splashColor: Colors.transparent,
        highlightColor: Colors.transparent,
        icon: AnimatedSwitcher(
          duration: const Duration(milliseconds: 350),
          transitionBuilder: (child, anim) => RotationTransition(
            turns: child.key == const ValueKey('icon1') ? Tween<double>(begin: 1, end: 0).animate(anim) : Tween<double>(begin: 0, end: 1).animate(anim),
            child: ScaleTransition(scale: anim, child: child),
          ),
          child: ThemeService().isSavedDarkMode() == true ? const Icon(Icons.dark_mode, key: ValueKey("icon2")) : const Icon(Icons.light_mode, key: ValueKey("icon1")),
        ),
        onPressed: () => setState(() {ThemeService().changeTheme();}),
      ),
Carolanncarole answered 19/7, 2023 at 10:46 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Designing
O
0

2023.9 Update:Now you can use AnimatedRotation Widget. It's much easier, no AnimationController is needed.

From official docs:

class LogoRotate extends StatefulWidget {
  const LogoRotate({super.key});

  @override
  State<LogoRotate> createState() => LogoRotateState();
}

class LogoRotateState extends State<LogoRotate> {
  double turns = 0.0;

  void _changeRotation() {
    setState(() => turns += 1.0 / 8.0);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        ElevatedButton(
          onPressed: _changeRotation,
          child: const Text('Rotate Logo'),
        ),
        Padding(
          padding: const EdgeInsets.all(50),
          child: AnimatedRotation(
            turns: turns,
            duration: const Duration(seconds: 1),
            child: const FlutterLogo(),
          ),
        ),
      ],
    );
  }
}
Oligocene answered 21/9, 2023 at 9:13 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.