Nick
Nick

Reputation: 4483

How to rotate an image using Flutter AnimationController and Transform?

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,
          );
        },
      ),
    );
  }
}

Upvotes: 55

Views: 86154

Answers (11)

Fatih NALCI
Fatih NALCI

Reputation: 31

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();}),
      ),

Upvotes: 0

hanswim
hanswim

Reputation: 1242

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(),
          ),
        ),
      ],
    );
  }
}

Upvotes: 0

Luis_RH
Luis_RH

Reputation: 403

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(),
          ),
        ),
      ],
    );
  }
}

Upvotes: 5

CopsOnRoad
CopsOnRoad

Reputation: 267404

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),
        ),
      ),
    );
  }
}

Upvotes: 52

Faiz
Faiz

Reputation: 6980

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,
      ),
    );
  }
}

Upvotes: 0

WSBT
WSBT

Reputation: 36323

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

Upvotes: 69

Amir Mehrabi
Amir Mehrabi

Reputation: 95

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,
            )
    );
  }
}

Upvotes: 2

dr.mStar
dr.mStar

Reputation: 101


    _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()),
        ));    

Upvotes: 1

Supun Dewapriya
Supun Dewapriya

Reputation: 763

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,
              );
            }),

      ],),
    );
  }
}

Upvotes: 4

Supun Dewapriya
Supun Dewapriya

Reputation: 763

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,
          );
        },
      ),
    );
  }
}

Upvotes: 4

Andrii Turkovskyi
Andrii Turkovskyi

Reputation: 29438

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);

Upvotes: 43

Related Questions