Flutter AnimatedList - Adding a CurvedAnimation to a SlideTransition - flutter

I've managed to get to a point where I have an AnimatedList which will slide in newly added items. A Dismissible widget that wraps my list items controls the remove animation. My question is how can I add some sort of animation curve to the SlideTransition so that I can control how the new list item appears when it slides in. Here's where I'm at so far:
#override
Widget build(BuildContext context) {
final checklists = Provider.of<Checklists>(context);
return AnimatedList(
key: listKey,
initialItemCount: checklists.lists.length,
itemBuilder: (ctx, i, animation) {
return SlideTransition(
position: CurvedAnimation(parent: ).drive(child) // <- this line needs changing
child: _buildListItem(checklists.lists[i], i),
);
},
);
}
I'm not sure what to do with the position argument. Previously for the standard SlideTransition I was simply using
animation.drive(Tween(begin: Offset(0.2, 0), end: Offset(0.0, 0))),
which works fine, but is lacking a curve ease. Any ideas?
Edit
Heres the complete .dart file for clarity as well as where I insert a new item from the parent widget:
GlobalKey<AnimatedListState> recentListsAnimationKey = GlobalKey();
class RecentLists extends StatefulWidget {
#override
_RecentListsState createState() => _RecentListsState();
}
class _RecentListsState extends State<RecentLists>
with TickerProviderStateMixin {
Widget _buildListItem(Checklist list, int listIndex) {
return Dismissible(
key: ObjectKey(list.id),
direction: DismissDirection.endToStart,
background: Container(
alignment: AlignmentDirectional.centerEnd,
color: Theme.of(context).accentColor,
child: Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
child: Icon(
Icons.delete,
color: Colors.white,
),
),
),
child: ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (ctx) => ListItemsScreen(list.id),
),
);
},
title: Text(list.name),
leading: Checkbox(
value: list.completed,
onChanged: (value) {
setState(() {
list.completed = value;
});
},
),
),
onDismissed: (direction) {
_onDeleteList(list, listIndex);
},
);
}
void _onDeleteList(Checklist list, int listIndex) {
Provider.of<Checklists>(context).deleteList(list.id);
recentListsAnimationKey.currentState
.removeItem(listIndex, (_, __) => Container());
Scaffold.of(context).showSnackBar(
SnackBar(
action: SnackBarAction(
label: 'UNDO',
onPressed: () {
Provider.of<Checklists>(context).undoDeleteList(list, listIndex);
recentListsAnimationKey.currentState
.insertItem(listIndex, duration: Duration(milliseconds: 100));
},
),
content: Text(
'List deleted',
style: TextStyle(color: Theme.of(context).accentColor),
),
),
);
}
AnimationController _controller;
Animation<Offset> _position;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(milliseconds: 200),
vsync: this,
);
_position = Tween(
begin: Offset(0.5, 0),
end: Offset(0.0, 0),
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.decelerate,
),
);
_controller.forward();
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
final checklists = Provider.of<Checklists>(context);
return AnimatedList(
key: recentListsAnimationKey,
initialItemCount: checklists.lists.length,
itemBuilder: (ctx, i, animation) {
return SlideTransition(
position: _position,
child: _buildListItem(checklists.lists[i], i),
);
},
);
}
}
Here is where I insert new items into the list. No slide animation is shown.
void createNewList(BuildContext context) {
if (nameController.text.isNotEmpty) {
Provider.of<Checklists>(context).addList(nameController.text);
recentListsAnimationKey.currentState.insertItem(0, duration: Duration(milliseconds: 100));
nameController.clear();
}
Navigator.of(context).pop();
}

Use the Animation.drive function with a CurveTween chained to your offset Tween. Your itemBuilder should look like this:
itemBuilder: (ctx, i, animation) {
return SlideTransition(
position: animation.drive(Tween(begin: Offset(2, 0.0), end: Offset(0.0, 0.0))
.chain(CurveTween(curve: Curves.elasticInOut))),
child: _buildListItem(checklists.lists[i], i),
);
},

In Flutter, Animation just a class which change data from start to end based on percent provided from AnimationController. You have to prepare position which instance of Animation<Offset>.
class DemoWidget extends StatefulWidget {
#override
_DemoWidgetState createState() => _DemoWidgetState();
}
class _DemoWidgetState extends State<DemoWidget>with TickerProviderStateMixin {
AnimationController _controller;
Animation<Offset> _position;
#override
Widget build(BuildContext context) {
final checklists = Provider.of<Checklists>(context);
return AnimatedList(
key: listKey,
initialItemCount: checklists.lists.length,
itemBuilder: (ctx, i, animation) {
return SlideTransition(
position: _position,
child: _buildListItem(checklists.lists[i], i),
);
},
);
}
#override
initState() {
super.initState();
_controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
_position = Tween(begin: Offset(0.2, 0), end: Offset(0.0, 0)).animate(CurvedAnimation(parent: _controller, curve: Curves.decelerate));
_controller.forward();
}
#override
dispose() {
_controller.dispose();
super.dispose();
}
}

Related

Flutter - Custom widget animation state reversed in Gridview

I have a gridview with a couple of custom cards that when selected will change color to indicate to the user that they have selected the card. When I scroll down and return to the previously selected card, the color changes like it was never selected.
At first, I thought it was a key issue but that didn't solve anything.
This is the code I have
// Code for the Gridview
GridView.builder(
padding: EdgeInsets.all(Insets.sm),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: Insets.sm,
crossAxisSpacing: Insets.sm,
),
itemCount: categories.length,
itemBuilder: (BuildContext context, int index) {
return CategoryCard(
key: UniqueKey(),
category: categories[index],
onTap: (isSelected) {
(isSelected)
? game.categories.add(categories[index])
: game.categories.remove(categories[index]);
},
);
},
),
// This is the code for the custom widget
class CategoryCard extends StatefulWidget {
const CategoryCard({
super.key,
required this.category,
required this.onTap,
});
final Category category;
final Function(bool) onTap;
#override
State<CategoryCard> createState() => _CategoryCardState();
}
class _CategoryCardState extends State<CategoryCard>
with TickerProviderStateMixin {
late AnimationController controller;
late Animation<Color?> containerBackground;
late Animation<Color?> imageBackground;
late Animation<Color?> textColor;
late CurvedAnimation curve;
bool isSelected = true;
#override
void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
curve = CurvedAnimation(
parent: controller,
curve: Curves.easeInOut,
);
containerBackground =
ColorTween(begin: Colors.white, end: AppColors.blue200)
.animate(controller)
..addListener(() => setState(() {}));
imageBackground =
ColorTween(begin: AppColors.blue50, end: AppColors.blue100)
.animate(controller)
..addListener(() => setState(() {}));
textColor = ColorTween(begin: AppColors.blue300, end: Colors.white)
.animate(controller)
..addListener(() => setState(() {}));
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
void animateColor() {
if (isSelected) {
controller.forward();
} else {
controller.reverse();
}
widget.onTap(isSelected);
isSelected = !isSelected;
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => {animateColor()},
child: Container(
decoration: BoxDecoration(
color: containerBackground.value,
borderRadius: Corners.lgBorder,
),
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Container(
padding: EdgeInsets.all(Insets.xs),
decoration: BoxDecoration(
color: imageBackground.value,
borderRadius: Corners.lgBorder,
),
clipBehavior: Clip.antiAlias,
child: Image.asset(
"assets/images/${widget.category.name.toLowerCase()}.png",
width: 78,
height: 78,
),
),
SizedBox(height: Insets.med),
Text(
widget.category.name,
style: TextStyles.body1.copyWith(color: textColor.value),
)
]),
),
);
}
}
Any help or explanation on why this is happening is appreciated.

animation with bloc package on flutter

please check my code I want to use this animation with the bloc package,
and also I want to use that without StatefulWidget class :
class LoadingScreen extends StatefulWidget {
const LoadingScreen({Key? key}) : super(key: key);
#override
State<LoadingScreen> createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen>
with TickerProviderStateMixin {
late AnimationController controller;
late AnimationController controller2;
late Animation<Offset> disk;
late Animation<Offset> offset;
int diskPicW = 0;
#override
void initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
controller2 = AnimationController(
vsync: this, duration: Duration(seconds: 1, milliseconds: 500));
offset = Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset.zero)
.animate(controller);
disk = Tween<Offset>(begin: Offset(-1.0, 0.0), end: Offset.zero)
.animate(controller2);
controller.forward();
controller2.forward();
Timer(Duration(seconds: 2, milliseconds: 500), (() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FirstPage(),
));
}));
}
SizeController() {
setState(() {});
}
#override
void dispose() {
super.dispose();
controller.dispose();
controller2.dispose();
}
#override
Widget build(BuildContext context) {
print(MediaQuery.of(context).size.width);
print(MediaQuery.of(context).size.height);
return Scaffold(
backgroundColor: color3,
body: Stack(
children: [
SlideTransition(
position: offset,
child: Center(
child: Image.asset(
'assets/001.png',
width: 150,
height: 150,
),
),
),
SlideTransition(
position: disk,
child: AnimatedBuilder(
animation: controller2.view,
builder: (context, child) {
return Transform.rotate(
angle: controller2.value * 2 * pi,
child: child,
);
},
child: Center(
child: Image.asset(
'assets/disk2.png',
width: 130,
height: 130,
),
),
),
),
SlideTransition(
position: offset,
child: Center(
child: Image.asset(
'assets/002.png',
width: 150,
height: 150,
),
),
)
],
),
);
}
}
This is my simple animation code
How can I run this animation using the bloc package?
I want without using the StatefulWidget class make that
I want to use the bloc package and I don't know how
Please teach me, thank you

How can i reverse the animation using SizeTransition

i have this code . my animation comse from top to bottom , but How can i reverse it to other side which from bottom to top ..
as we can see it be hidden on the top then it move to down but i need to reverse it to be hidden on the bottom and it move to top
class VariableSizeContainerExample extends StatefulWidget {
VariableSizeContainerExample();
#override
_VariableSizeContainerExampleState createState() => _VariableSizeContainerExampleState();
}
class _VariableSizeContainerExampleState extends State<VariableSizeContainerExample> with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
);
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.fastLinearToSlowEaseIn,
);
}
_toggleContainer() {
print(_animation.status);
if (_animation.status != AnimationStatus.completed) {
_controller.forward();
} else {
_controller.animateBack(0, duration: Duration(seconds: 1));
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
children: [
TextButton(
onPressed: () => _toggleContainer(),
child: Text("Toggle container visibility"),
),
SizeTransition(
sizeFactor: _animation,
axis: Axis.vertical,
child: Container(
child: Text(
"This can have variable size",
style: TextStyle(fontSize: 40),
),
),
),
Text("This is below the above container"),
],
),
),
),
);
}
}
The default animation start from center then will expand.
To control this, you can use axisAlignment on SizeTransition.
A value of 1.0 indicates the bottom or end, depending upon the [axis].
A value of 0.0 (the default) indicates the center for either [axis] value.
To fixed-bottom(hide-top) use axisAlignment:1 and to fixed top(hide-bottom) axisAlignment:-1
SizeTransition(
sizeFactor: _animation,
axisAlignment: -1, //play with 1 and -1
More about SizeTransition.
test widget
void main(List<String> args) =>
runApp(MaterialApp(home: Scaffold(body: VariableSizeContainerExample())));
class VariableSizeContainerExample extends StatefulWidget {
VariableSizeContainerExample({Key? key}) : super(key: key);
#override
State<VariableSizeContainerExample> createState() =>
_VariableSizeContainerExampleState();
}
class _VariableSizeContainerExampleState
extends State<VariableSizeContainerExample>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 4),
vsync: this,
)..addListener(() {
setState(() {});
});
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.fastLinearToSlowEaseIn,
);
}
#override
void dispose() {
super.dispose();
}
void _toggleContainer() {
debugPrint(_animation.status.toString());
if (_animation.status != AnimationStatus.completed) {
_controller.forward();
} else {
_controller.animateBack(0, duration: Duration(seconds: 1));
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
children: [
TextButton(
onPressed: () => _toggleContainer(),
child: Text("Toggle container visibility"),
),
SizeTransition(
sizeFactor: _animation,
axisAlignment: 1,
/// also try -1
axis: Axis.vertical,
child: Container(
child: const Text(
"This can have variable size",
style: TextStyle(fontSize: 66),
),
),
),
const Text("This is below the above container"),
],
),
);
}
}

How to animate the items rendered initially using Animated List in flutter

I am using Animated List in flutter to load a list class, while adding or removing the items, the animation works but when the list is initially loaded, the animation does not work. Is there a way to animate items when initially loading the list.
class AnimationTest extends StatefulWidget {
#override
_AnimationTestState createState() => _AnimationTestState();
}
class _AnimationTestState extends State<AnimationTest> with SingleTickerProviderStateMixin {
AnimationController _controller;
#override
void initState() {
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return AnimatedList(
key: _listKey,
initialItemCount: 3,
itemBuilder: (BuildContext context, int index, Animation animation) {
return SlideTransition(
position: animation.drive(Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset.zero)
.chain(CurveTween(curve: Curves.decelerate))),
child: Row(
children: <Widget>[
Expanded(
child: InkWell(
onTap: () => _listKey.currentState.insertItem(0,duration: Duration(milliseconds: 600)),
child: Container(
padding: EdgeInsets.only(left: 10, right: 10),
height: 100,
child: Card(
margin: EdgeInsets.symmetric(vertical: 4.0),
color: Theme.of(context).backgroundColor,
)),
),
),
],
),
);
},
);
}
}
Because AnimatedList can only animate when adding/removing item in the list. You need to add each item individually by using insertItem or removeItem from AnimatedListState. One way to achieve a nice loading effect is to delay each time you insert/remove item.
Here is the code to chain Future so that each item is loaded one after another after a specified delay
var future = Future(() {});
for (var i = 0; i < fetchedList.length; i++) {
future = future.then((_) {
return Future.delayed(Duration(milliseconds: 100), () {
// add/remove item
});
});
}
From there you can create a loadItems() method to initialize all items in the AnimatedList in initState(). Remember to update both the underlying data structure (_listItems) and AnimatedList itself for it to work.
var _listItems = <Widget>[];
final GlobalKey<AnimatedListState> _listKey = GlobalKey();
#override
void initState() {
super.initState();
_loadItems();
}
void _loadItems() {
// fetching data from web api, local db...
final fetchedList = [
ListTile(
title: Text('Economy'),
trailing: Icon(Icons.directions_car),
),
ListTile(
title: Text('Comfort'),
trailing: Icon(Icons.motorcycle),
),
ListTile(
title: Text('Business'),
trailing: Icon(Icons.flight),
),
];
var future = Future(() {});
for (var i = 0; i < fetchedList.length; i++) {
future = future.then((_) {
return Future.delayed(Duration(milliseconds: 100), () {
_listItems.add(fetchedList[i]);
_listKey.currentState.insertItem(i);
});
});
}
}
This is the complete example. I added 2 buttons in the app bar so you can play around with the animations
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'YourAwesomeApp',
home: PageWithAnimatedList(),
);
}
}
class PageWithAnimatedList extends StatefulWidget {
#override
_PageWithAnimatedListState createState() => _PageWithAnimatedListState();
}
class _PageWithAnimatedListState extends State<PageWithAnimatedList> {
var _listItems = <Widget>[];
final GlobalKey<AnimatedListState> _listKey = GlobalKey();
#override
void initState() {
super.initState();
_loadItems();
}
void _loadItems() {
// fetching data from web api, db...
final fetchedList = [
ListTile(
title: Text('Economy'),
trailing: Icon(Icons.directions_car),
),
ListTile(
title: Text('Comfort'),
trailing: Icon(Icons.motorcycle),
),
ListTile(
title: Text('Business'),
trailing: Icon(Icons.flight),
),
];
var future = Future(() {});
for (var i = 0; i < fetchedList.length; i++) {
future = future.then((_) {
return Future.delayed(Duration(milliseconds: 100), () {
_listItems.add(fetchedList[i]);
_listKey.currentState.insertItem(_listItems.length - 1);
});
});
}
}
void _unloadItems() {
var future = Future(() {});
for (var i = _listItems.length - 1; i >= 0; i--) {
future = future.then((_) {
return Future.delayed(Duration(milliseconds: 100), () {
final deletedItem = _listItems.removeAt(i);
_listKey.currentState.removeItem(i,
(BuildContext context, Animation<double> animation) {
return SlideTransition(
position: CurvedAnimation(
curve: Curves.easeOut,
parent: animation,
).drive((Tween<Offset>(
begin: Offset(1, 0),
end: Offset(0, 0),
))),
child: deletedItem,
);
});
});
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(icon: Icon(Icons.add), onPressed: _loadItems),
IconButton(icon: Icon(Icons.remove), onPressed: _unloadItems)
],
),
body: AnimatedList(
key: _listKey,
padding: EdgeInsets.only(top: 10),
initialItemCount: _listItems.length,
itemBuilder: (context, index, animation) {
return SlideTransition(
position: CurvedAnimation(
curve: Curves.easeOut,
parent: animation,
).drive((Tween<Offset>(
begin: Offset(1, 0),
end: Offset(0, 0),
))),
child: _listItems[index],
);
},
),
);
}
}
Live Demo

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