Flutter: Matrix4 Off-center rotation during animated transition - flutter

Description:
Hello, I am trying to animate the rotation of an object.
For this I use Matrix4 to control the point of rotation of my object.
I have a strange behavior during the animation transition.
Problem :
Why does my green square not maintain its rotation around its center during the animation?
The code :
class NodeV3View extends StatefulWidget {
const NodeV3View({
Key? key,
}) : super(key: key);
#override
State<NodeV3View> createState() => _NodeV3ViewState();
}
class _NodeV3ViewState extends State<NodeV3View> {
bool isExpand = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
var controller = Provider.of<CompteurProvider2>(context);
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints){
return Consumer<CompteurProvider2>(builder :(ctx , provider , child){
return GestureDetector(
onTap: () => setState(() {}),
child: Container(
color: Colors.yellow,
width: 300,
height: 300,
child: Stack(
children: [
Positioned(
left: 150 - 50,// => Yellow Square / 2 - Green Square / 2
top : 150 - 50,
child: InkWell(
onTap: (){
setState(() {
isExpand = !isExpand;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 500),
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.green,
),
transform: Matrix4Transform()
.rotateDegrees(
isExpand == true
? 180
: 0,
origin: Offset(50, 50)
)
.matrix4,
),
),
)
],
),
)
);
});
},
)
);
}
}
Any guidance on the best way to accomplish this would be appreciated.

Add transformAlignment: FractionalOffset.center to the AnimatedContainer.

i hope this one may be help you
this code for only one time rotate the box, but you will add conditions for your desire things
import 'dart:math';
import 'package:flutter/material.dart';
class TransformExample extends StatefulWidget {
const TransformExample({Key? key}) : super(key: key);
#override
State<TransformExample> createState() => _TransformExampleState();
}
class _TransformExampleState extends State<TransformExample>
with TickerProviderStateMixin {
late AnimationController animationController =
AnimationController(vsync: this, duration: const Duration(seconds: 2));
#override
void dispose() {
super.dispose();
animationController.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: InkWell(
onTap: () => setState(() {
animationController.forward();
}),
child: AnimatedBuilder(
animation: animationController,
child: Container(
height: 150.0,
width: 150.0,
color: Colors.blueGrey,
),
builder: (BuildContext context, Widget? child) {
return Transform.rotate(
angle: animationController.value * 2.0 * pi,
child: child,
);
}),
),
),
);
}
}

If you only want to rotate it along the z-axis, a much easier way is to use the RotationTransition widget, check out this existing answer here.
If you want to rotate along different axes, for example, making a 3D cube by rotating along x-axis and y-axis, you can check out this video tutorial here.

Related

How to make a spinning circle animation during a countdown in flutter?

I have a time widget that counts down 30 seconds. I have a circle around the time (I attached a screenshot below). I need to animate this circle so that when the time is counted down for 30 seconds, the circle spins, only the time reaches 00:00 the circle stops and does not spin, by pressing the button, the time counts down again for 30 seconds and the circle starts spinning. Tell me how to make an animation of a spinning circle?
class ResendLoader extends StatelessWidget {
const ResendLoader({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
context.read<TimerBloc>().add(const TimerStarted(duration: 30));
return BlocBuilder<TimerBloc, TimerState>(
buildWhen: (prev, state) => prev.runtimeType != state.runtimeType,
builder: (context, state) {
return Center(
child: Stack(
alignment: AlignmentDirectional.center,
children: [
SizedBox(
width: 70,
height: 70,
child: CustomPaint(
painter: RingPainter(
progress: 0.3,
taskCompletedColor: Colors.white,
taskNotCompletedColor:
constants.Colors.greyDark.withOpacity(0.5)),
),
),
_timerText(context),
],
),
);
},
);
}
class CirclePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final strokeWidth = size.width / 15.0;
final center = Offset(size.width / 2, size.height / 2);
final radius = (size.width - strokeWidth) / 2;
var paint1 = Paint()
..color = const Color(0xff63aa65)
..style = PaintingStyle.fill;
//a circle
canvas.drawCircle(center, radius, paint1);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
You can use AnimatedRotation widget and animate its turns like this
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(home: AnimatedCircle());
}
}
class AnimatedCircle extends StatefulWidget {
const AnimatedCircle({Key? key}) : super(key: key);
#override
State<AnimatedCircle> createState() => _AnimatedCircleState();
}
class _AnimatedCircleState extends State<AnimatedCircle> {
double rotation = 0;
int seconds = 30;
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
MaterialButton(
color: Colors.blue,
child: Text("Start Animation"),
onPressed: () {
seconds = 30;
rotation = 0;
startAnimation();
}),
SizedBox(
height: 20,
),
MaterialButton(
color: Colors.blue,
child: Text("Stop Animation"),
onPressed: () {
seconds = 0;
setState(() {});
}),
SizedBox(
height: 20,
),
AnimatedRotation(
turns: rotation,
duration: Duration(seconds: 1),
curve: Curves.linear,
child: Stack(
alignment: AlignmentDirectional.center,
children: [
SizedBox(
width: 70,
height: 70,
child: CustomPaint(
painter: RingPainter(
progress: 0.3,
taskCompletedColor: Colors.white,
taskNotCompletedColor:
constants.Colors.greyDark.withOpacity(0.5)),
),
),
SizedBox(
height: 20,
),
Text("Seconds: $seconds")
],
),
),
);
}
startAnimation() {
//To slow down the animation
rotation += 0.5;
seconds--;
setState(() {});
if (seconds >= 0) {
Future.delayed(Duration(seconds: 1), () {
startAnimation();
});
}
}
}
Use a FutureBuilder, the future is a this: Future.delayed(Duration(minutes: 1))
After a minute, the builder will update to complete. Change the minutes to whatever you want, you can do minutes, seconds, hours, etc.
In the builder, have an if statement to check the status. in the else, return a CircularProgressIndicator widget. That's what you want.
See the docs: https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
FYI, you have way more code than you need.

How to have the drawer push the content instead of going on top of it?

I'm trying to build something similar to the slack app (see screenshot below) where the navigation drawer pushes the screen away instead of going on top.
I've been trying with the Drawer component without success. I've also looked at PageView but it seems that the children need to take 100% of the width.
Does someone have an idea of how to implement it?
EDIT
A similar result can be achieved with a Stack and AnimatedPositioned
class SlidingDrawer extends StatefulWidget {
final Widget drawer;
final Widget child;
final int swipeSensitivity;
final double drawerRatio;
final Color overlayColor;
final double overlayOpacity;
final int animationDuration;
final Curve animationCurve;
SlidingDrawer({
Key key,
#required this.drawer,
#required this.child,
this.swipeSensitivity = 25,
this.drawerRatio = 0.8,
this.overlayColor = Colors.black,
this.overlayOpacity = 0.5,
this.animationDuration = 500,
this.animationCurve = Curves.ease,
}) : super(key: key);
#override
_SlidingDrawerState createState() => _SlidingDrawerState();
}
class _SlidingDrawerState extends State<SlidingDrawer> {
bool _opened = false;
void open() {
setState(() {
_opened = true;
});
}
void close() {
setState(() {
_opened = false;
});
}
#override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
final drawerWidth = width * widget.drawerRatio;
return GestureDetector(
onHorizontalDragUpdate: (details) {
if (details.delta.dx > widget.swipeSensitivity) {
open();
} else if (details.delta.dx < -widget.swipeSensitivity) {
close();
}
},
child: SizedBox(
width: width,
height: height,
child: Stack(
children: [
AnimatedPositioned(
width: drawerWidth,
height: height,
left: _opened ? 0 : -drawerWidth,
duration: Duration(milliseconds: widget.animationDuration),
curve: widget.animationCurve,
child: Container(
color: Colors.amber,
child: widget.drawer,
),
),
AnimatedPositioned(
height: height,
width: width,
left: _opened ? drawerWidth : 0,
duration: Duration(milliseconds: widget.animationDuration),
curve: widget.animationCurve,
child: Stack(
fit: StackFit.expand,
children: [
widget.child,
AnimatedSwitcher(
duration: Duration(milliseconds: widget.animationDuration),
switchInCurve: widget.animationCurve,
switchOutCurve: widget.animationCurve,
child: _opened
? GestureDetector(
onTap: () {
setState(() {
_opened = false;
});
},
child: Container(
color: widget.overlayColor.withOpacity(
widget.overlayOpacity,
),
),
)
: null,
)
],
),
),
],
),
),
);
}
}
ORIGINAL ANSWER
As pointed out by #Yadu in the comment
you could use Single child horizontal scroll view (with disabled scroll physics) with Scrollable.ensureVisible(context) to show the menu
using an horizontal scroll view is working.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _drawerOpened = false;
final drawerKey = new GlobalKey();
final mainKey = new GlobalKey();
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
child: Row(
children: [
Container(
key: drawerKey,
color: Colors.green,
width: MediaQuery.of(context).size.width * 0.8,
),
SizedBox(
key: mainKey,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Scaffold(
appBar: AppBar(
title: Text("My Page"),
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: _toggleDrawer,
),
),
body: Container(
color: Colors.yellow,
width: MediaQuery.of(context).size.width,
),
),
),
],
),
);
}
void _toggleDrawer() {
setState(() {
_drawerOpened = !_drawerOpened;
});
if (_drawerOpened) {
Scrollable.ensureVisible(drawerKey.currentContext);
} else {
Scrollable.ensureVisible(mainKey.currentContext);
}
}
}

How to create a flutter stateful widget that rotate its child?

I'd like to create a stateful widget that embed other widget(s) to apply some form of custom rendering operations (such as rotation for example)
So I'd like to use my widget from a parent widget as follows:
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _buildView(),
floatingActionButton: StreamBuilder<bool>(
stream: FlutterBlue.instance.isScanning,
initialData: false,
builder: (c, snapshot) {
if (snapshot.data) {
return FloatingActionButton(
child: Stack(alignment: Alignment.center, children: [
RotatingWidget(
child: ArcText(
radius: 34,
text: 'Radar scanning… | Radar scanning…',
textStyle: TextStyle(fontSize: 12, color: Colors.white),
startAngle: -3 * math.pi / 4,
),
),
Icon(Icons.stop),
]),
onPressed: () => FlutterBlue.instance.stopScan(),
backgroundColor: Colors.red,
);
}
else
// Etc.
I came up with such a widget as follows, but I wonder how could I get the child to render it?
// Rotating button for the radar scanning
class RotatingWidget extends StatefulWidget {
final Widget child;
const RotatingWidget({Key key, #required this.child}) : super(key: key);
#override
_RotatingWidgetState createState() => _RotatingWidgetState();
}
class _RotatingWidgetState extends State<RotatingWidget>
with SingleTickerProviderStateMixin {
AnimationController _controller;
#override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 2))
..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,
);
},
// ===== HOW TO GET THE CHILD PASSED TO THE CURRENT WIDGET ? ====
child: this.state.child//FlutterLogo(size: 200),
),
);
}
}
Merits go to #pskink for his quick answer:
You access to the child by writing:
child: widget.child
instead of my wrong initial child: this.child

How to animate the swap of 2 items in a Row?

I want to make something very simple. There's a Row with 2 widgets. When I press a button, they swap orders. I want this order swap to be animated.
I've loked at AnimatedPositioned but it requires a Stack. What would be the best way of doing such thing?
I thought Animating position across row cells in Flutter answered this but it's another different problem
You can easily animate widgets in a Row with SlideAnimation. Please see the code below or you may directly run the code on DartPad https://dartpad.dev/e5d9d2c9c6da54b3f76361eac449ce42 Just tap on the colored box to swap their positions with an slide animation.
SlideAnimation
Animates the position of a widget relative to its normal position.
The translation is expressed as an Offset scaled to the child's size.
For example, an Offset with a dx of 0.25 will result in a horizontal
translation of one quarter the width of the child.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
AnimationController _controller;
List<Animation<Offset>> _offsetAnimation;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
);
_offsetAnimation = List.generate(
2,
(index) => Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: Offset(index == 0 ? 1 : -1, 0.0),
).animate(_controller),
);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
void _animate() {
_controller.status == AnimationStatus.completed
? _controller.reverse()
: _controller.forward();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Flutter Demo Row Animation")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
BoxWidget(
callBack: _animate,
text: "1",
color: Colors.red,
position: _offsetAnimation[0],
),
BoxWidget(
callBack: _animate,
text: "2",
color: Colors.blue,
position: _offsetAnimation[1],
)
],
),
RaisedButton(
onPressed: _animate,
child: const Text("Swap"),
)
],
),
),
);
}
}
class BoxWidget extends StatelessWidget {
final Animation<Offset> position;
final Function callBack;
final String text;
final Color color;
const BoxWidget(
{Key key, this.position, this.callBack, this.text, this.color})
: super(key: key);
#override
Widget build(BuildContext context) {
return SlideTransition(
position: position,
child: GestureDetector(
onTap: () => callBack(),
child: Container(
margin: const EdgeInsets.all(10),
height: 50,
width: 50,
color: color,
child: Center(
child: Container(
height: 20,
width: 20,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
child: Center(child: Text(text)),
),
),
),
),
);
}
}

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,
);
},
),
);
}
}
Full example (null safe):
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
Screenshot (Null Safe)
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),
),
),
);
}
}
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);
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,
);
},
),
);
}
}
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,
);
}),
],),
);
}
}
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(),
),
),
],
);
}
}
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,
)
);
}
}
_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()),
));
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,
),
);
}
}