I'm trying to animate rotation of icon inside custom button to 180 degree on each press. I'm bit confused from the flutter documentation. I know I should use RotationTransition but I just can not find out how.. Here is my button
SizedBox.fromSize(
size: Size(50, 50),
child: ClipOval(
child: Material(
color: Colors.blue,
child: InkWell(
onTap: () {},
splashColor: Colors.black12,
child: RotationTransition(. //<== that is where I get
child: Icon(
Icons.filter_list, //rotate this icon
color: Colors.white,
),
),
),
),
),
),
Basically, you need a Stateful widget with an AnimationController which creates controls the animation. It's important to create that controller on the initState() method, and dispose it on the dispose() method to prevent possible errors.
Once you have the controller, you can use a bool to store the rotation direction and an Animation controlled by the Animation controller to rotate the widget. First, it goes from 0 to 0.5, and then from 0.5 to 1.
The code can be like this. You can also take a look at this codepen I created for the example.
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: MyWidget(),
),
);
}
class MyWidget extends StatefulWidget{
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget>
with SingleTickerProviderStateMixin{
AnimationController _controller;
Animation<double> _animation;
bool dir = true;
#override
void initState(){
_controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
super.initState();
}
#override
void dispose(){
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
_animation = Tween<double>(
begin: dir ? 0:0.5,
end: dir ? 0.5:1
).animate(_controller);
return Scaffold(
body: Center(
child: RotationTransition(
turns: _animation,
child: RaisedButton(
child: Text("Rotate"),
onPressed: (){
_controller.forward(
from: 0
);
setState(() {dir = !dir;});
}
)
)
),
);
}
}
Related
So I am trying to find a way where I can press a button, change the background color then get back to the original color using tween.
Is there anyway I could possibly achieve this?
Here is an example of How you can change background with a tween.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
// Remove the debug banner
debugShowCheckedModeBanner: false,
title: 'Tween',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
late AnimationController _controller;
late Animation<Color?> _color;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 5),
vsync: this,
);
_color =
ColorTween(begin: Colors.blue, end: Colors.amber).animate(_controller);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
const SizedBox(height: 20),
AnimatedBuilder(
animation: _color,
builder: (BuildContext _, Widget? __) {
return Container(
width: 500,
height: 300,
decoration: BoxDecoration(
color: _color.value, shape: BoxShape.rectangle),
);
},
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () {
_controller.forward();
},
child: Text('Change background'),
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () {
_controller.reverse();
},
child: Text('back to Orignal'),
),
],
),
);
}
}
I'm making a Splash Screen in my app.
In my splash screen, I want to animate(zoom in) my logo
I want to animate my logo, as soon as the screen starts.
This is my code so far...
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
final _splashDelay = 2000;
double _height = 10.0;
#override
void initState() {
// TODO: implement initState
super.initState();
_loadWidget();
}
_loadWidget() async {
var _duration = Duration(milliseconds: _splashDelay);
return Timer(_duration, navigationPage);
}
void navigationPage() {
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => LoginScreen()));
}
#override
Widget build(BuildContext context) {
FlutterStatusbarcolor.setStatusBarColor(Colors.red[900]);
FlutterStatusbarcolor.setStatusBarWhiteForeground(true);
return Scaffold(
body: Stack(
children: [
SafeArea(
child: Container(
width: double.infinity,
height: double.infinity,
margin: EdgeInsets.symmetric(
horizontal: 15,
vertical: 30,
),
child: Card(
elevation: 4.5,
child: Center(
child: AnimatedContainer(
duration: Duration(milliseconds: 2000),
height: _height,
child: Image.asset('assets/images/logo.png'),
),
),
),
),
),
],
),
);
}
}
What I want is, to change the height of the AnimatedContainer() from 10 to 100 as soon as this screen starts.
I've been trying to achieve this since 3hrs now, but couldn't help myself get through. Now I'm seeking for your help/guidance. Thank you.
You must create an AnimationController and TweenAnimation that goes from the begin (10) to the end (100).
In this case, the controller is just for (redundant, I know) control the animation and when it should start.
When you create a Tween, and apply the method animate() you're just saying that you want the animation to start at the begin of this tween and end at the end of it within the time that you specified in the controller Duration.
final _splashDelay = 2000;
Animation height;
AnimationController _controller;
#override
void initState() {
// TODO: implement initState
super.initState();
_controller=AnimationController(vsync: this, duration: Duration(milliseconds:_splashDelay,),)..forward();
_controller.addListener(
() {
setState(() {});
},
);
height=Tween<double>(begin:10, end:100,).animate(_controller);
_loadWidget();
}
Then, when you're building your AnimatedContainer, you must provide height: _height.value
Here you're just saying "Flutter, please change the value of this variable from 10 to 100 in a 2000 milliseconds interval, and use this value to draw the height of this Container"
Please note the you must add the mixin SingleTickerProviderStateMixin to your state. If you don't, vsync: this won't work.
You need a ScaleTransition widget to achieve your goal.
You can checkout the working sample of your code below:
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin {
final _splashDelay = 2000;
double _height = 10.0;
AnimationController _animationController;
#override
void initState() {
// TODO: implement initState
_animationController =
AnimationController(vsync: this, duration: const Duration(seconds: 2));
_animationController.forward();
super.initState();
_loadWidget();
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
_loadWidget() async {
var _duration = Duration(milliseconds: _splashDelay);
return Timer(_duration, navigationPage);
}
void navigationPage() {
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => LoginScreen()));
}
#override
Widget build(BuildContext context) {
FlutterStatusbarcolor.setStatusBarColor(Colors.red[900]);
FlutterStatusbarcolor.setStatusBarWhiteForeground(true);
return Scaffold(
body: Stack(
children: [
SafeArea(
child: Container(
width: double.infinity,
height: double.infinity,
margin: EdgeInsets.symmetric(
horizontal: 15,
vertical: 30,
),
child: Card(
elevation: 4.5,
child: Center(
child: ScaleTransition(
scale: _animationController,
child: Image.asset('assets/images/logo.png'),
),
),
),
),
),
],
),
);
}
}
I am having some problems with an animation I'm trying to do in Flutter using Dart. I am trying to incrementally increase the height of a box when the user clicks a button. Below is a very simple example of what I am trying to achieve. My problem is that the smooth animation only works for the first click but after that there is no animation, the box only gets larger.
Is there a way to fix this problem?
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Size Animation'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
double _myHeight = 310;
double _counter = 30;
double _target = 10;
#override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: Duration(seconds: 1));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Container(
alignment: Alignment.center,
child: Column(
children: <Widget>[
FlatButton(
child: Text('Reset me'),
color: Colors.red,
onPressed: () {
_target = 10;
_animationController.reset();
},
),
FlatButton(
child: Text('Click me'),
color: Colors.blue,
onPressed: () {
if (_target < _myHeight) {
setState(() {
_target += _counter;
});
}
_animationController.forward();
},
),
AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Container(
color: Colors.green,
width: 80,
height: _animationController.value * _target,
);
}),
],
),
),
),
);
}
}
You can easily reach this just by having a simple AnimatedContainer, that will automatically animate itself whenever one of it's proprierties changes, so your widget would look like this:
AnimatedContainer(
duration: const Duration(seconds: 1),
color: Colors.green,
width: 80,
height: _target
)
That way when _target value changes with setState value, your widget would animate the height.
Your current animation is working only the first time, because actually your are just running the animationController only once, then you recall the forward() again and again, but your animation has already been animated so, there's no forward, the value is going from 0 to 1 only the first time, then everytime you call the forward() method the animation is already at value 1, so you see no animation. One way you could do that if you really wanna keep this animation with an AnimatedBuilder you should give it a Tween instead of your animationController
I am trying to make a screen that
an image moves to a specific locatiob by clikcing a button.
I found an animation, AnimatedAligned, however this class seems not allow the widget to be located back to the original location.
Any guru knows which animation can be used in this case?
Check this out...
class SlideTransitionHome extends StatefulWidget {
#override
_SlideTransitionHomeState createState() => _SlideTransitionHomeState();
}
class _SlideTransitionHomeState extends State<SlideTransitionHome>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Tween<Offset> controllerTween = Tween<Offset>(begin: Offset.zero, end: Offset(1,1));
#override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: SlideTransition(
position: _controller.drive(controllerTween),
child: Container(
decoration: BoxDecoration(
color: Colors.pink,
borderRadius: BorderRadius.circular(10),
),
width: 100,
height: 100,
),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){
_controller.isDismissed ? _controller.forward() : _controller.reverse();
},
),
);
}
}
The Output:
UPDATE:
If you want it to animate to the center of the top, use this as the tween.
Tween<Offset> controllerTween = Tween<Offset>(begin: Offset.zero, end: Offset(0,-2.55));
The output:
I am using the below code to perform animation-grow and shrink animation of the icon but for it, I have to click on the icon, I want the animation repetitive once we on the screen.
return new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new IconButton(
onPressed: () {
setState(() {
if (_resized) {
_resized = false;
_height = 20.0;
} else {
_resized = true;
_height = 40.0;
}
});
},
icon: Icon(Icons.calendar_today, size: _height),
color: _color,
),
],
),
);
I want the output like below where the outer portion continuously grows and shrink.
You can use several approaches to this problem. My preferable would be to use AnimationController that repeats itself.
animationController = AnimationController(
vsync: this,
duration: Duration(seconds: 1),
)
..forward()
..repeat(reverse: true);
You can for instance animate the size of the padding around the button. I would use circular containers around the IconButton.
In order to do that you need to initialize AnimationController in your state. Remember about disposing it when the lifecycle of widget ends.
Here is a sample on codepen and dartpad:
https://codepen.io/orestesgaolin/pen/MWajRGV
https://dartpad.dartlang.org/ca4838f17ea6061cf0212a4b689eaf2a
And full source code can be found in this gist
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Animated Icon',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController animationController;
#override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: Duration(seconds: 1),
)
..forward()
..repeat(reverse: true);
}
#override
void dispose() {
animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.blue,
child: Center(
child: AnimatedBuilder(
animation: animationController,
builder: (context, child) {
return Container(
decoration: ShapeDecoration(
color: Colors.white.withOpacity(0.5),
shape: CircleBorder(),
),
child: Padding(
padding: EdgeInsets.all(8.0 * animationController.value),
child: child,
),
);
},
child: Container(
decoration: ShapeDecoration(
color: Colors.white,
shape: CircleBorder(),
),
child: IconButton(
onPressed: () {},
color: Colors.blue,
icon: Icon(Icons.calendar_today, size: 24),
),
),
),
),
),
);
}
}