how can we change the acceleration of the animation in duration or make some stops in it's duration?
for example scale a widget to 2x in 3 second than stop for a second than scale it for another 2x in 3 seconds.
AnimationController_anim1 = AnimationController(
vsync: this,
duration: Duration(milliseconds: 3000),
);
ScaleTransition(
scale: Tween(begin: 1.0, end: 2).animate(_anim1),
child: ClipRect(
clipBehavior: Clip.hardEdge,
child: OverflowBox(
maxHeight: 70,
maxWidth: 70,
child: Center(
child: Container(
decoration: BoxDecoration(
color: Colors.white38,
shape: BoxShape.circle,
),
),
),
),
),
)
You can use Curve class which provides a way to map the unit interval of animation to the desired unit interval that your want
for example, curves should implement a transform function whic are mapper that receives a time value in a range of 0,1 which indicates animations current time progress and you can return a value to indicate what should be the new progress of the animation for example you can say if time is greater than 0 then return time2 which speeds up your animation as 2x also note that you should are allowed to return value in the range of 0 to 1 so in this example, your should bound the time2 to be at most 1
Here is link to Curve class documentation :
https://api.flutter.dev/flutter/animation/Curve-class.html
also, there are a few ready to use curves in the Curves class that you can already use or look to the implementation of those to inspire :
https://api.flutter.dev/flutter/animation/Curves-class.html
as I searched around, I found the solution in two different ways, one is what Amir Hossein Mirzaei mentioned, which use Curve class, it is very powerful and flexible but it is a bit complicated and hard solution (beside being so powerful), but the second way is more handy which handled by TweenSequence as bellow :
1 - make an animation controller 2- make TweenSequence and add TweenSequenceItem for each step of animation 3- set it to widget
AnimationController _anim1 = AnimationController(
vsync: this,
duration: Duration(milliseconds: 8500),
//reverseDuration: Duration(milliseconds: 1000),
)..repeat(reverse: true);
Animation<double> _animation1 = TweenSequence(
<TweenSequenceItem<double>>[
TweenSequenceItem<double>(
tween: Tween<double>(begin: 1.0, end: 1.5),
weight: 23.5,
),
TweenSequenceItem<double>(
tween: ConstantTween<double>(1.5),
weight: 6.0,
),
TweenSequenceItem<double>(
tween: Tween<double>(begin: 1.5, end: 2.0),
weight: 23.5,
),
TweenSequenceItem<double>(
tween: ConstantTween<double>(2.0),
weight: 47.0,
),
],
).animate(_anim1);
ScaleTransition(
scale: _animation1,
child: ClipRect(
clipBehavior: Clip.hardEdge,
child: OverflowBox(
maxHeight: 70,
maxWidth: 70,
child: Center(
child: Container(
decoration: BoxDecoration(
color: Colors.white38,
shape: BoxShape.circle,
),
),
),
),
),
)
Related
I'm creating a custom checkbox-like widget that uses Card. I'm able to get the colors changing if the values are the same onTap. However, I want it to transition the color instead of it suddenly changing.
Here's my code:
return Card(
color: selected ? AppColors.primary : AppColors.primaryLight,
I'm relatively new to animations in Flutter, but coming from a strong Frontend/CSS understanding, the way I could achieve something like this is to add transition on a CSS property -- is there something similar to this in Flutter? If not, could someone point me in the right direction?
What I would do is instead of using the Card widget, I would use an AnimatedContainer and have the same condition as you for the color parameter. You will get a smooth transition when the selected value changes. However, you may need to also add boxShadow to have the same elevation effect as Card
AnimatedContainer(
duration: const Duration(milliseconds: 700),
curve: Curves.easeInOut,
decoration:BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 5,
spreadRadius: 5,
offset: Offset(0, 2),
),
],
color: selected ? AppColors.primary : AppColors.primaryLight,
),
)
One way to do this would be an AnimatedContainer
return Card(
child: AnimatedContainer(
duration: const Duration(milliseconds: 1000),
height: 200,
width: 200,
color: selected ? Colors.red : Colors.blue,
child: FooWidget(),
),
)
So I have a rotating container
Here is the working code:
#override
void initState() {
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 32),
)..repeat();
super.initState();
}
....
#override
Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
double screenWidth = MediaQuery.of(context).size.width;
return Container(
child: Column(
children: <Widget>[
SizedBox(
height: screenHeight,
child: Stack(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
],
),
Divider(),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Center(
child: AnimatedBuilder(
animation: _controller,
builder: (_, child) {
return Transform(
alignment: FractionalOffset.center,
transform: Matrix4.identity()
..setEntry(3, 2, 0.002)
..rotateY(0.5 * -math.pi)
..rotateZ(-0.1 * math.pi)
..rotateY((_controller.value - 0.6) * -math.pi)
..rotateX(0.5 * math.pi),
child: child,
);
},
child: Container(
//color: Colors.yellow.withOpacity(0.5),
height: 300,
width: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40),
boxShadow: [
BoxShadow(
color: Colors.yellow.withOpacity(0.5),
spreadRadius: 40,
//UNCOMMENTING THIS LINE CAUSES STRANGE BEHAVIOUR
//blurRadius: 50,
//offset: const Offset(0, 0),
),
],
),
),
//),
),
),
SizedBox(
height: 170,
)
],
),
],
),
),
],
),
);
}
However, when I uncomment the blurRadius line of code, it behaves strangely. Look how the container kind of gets distorted when it comes perpendicular to the screen.
I want it to be consistently blurred. This is something strange.
Shadows are very expensive for Flutter to draw, so it's bad to animate them like this because Flutter has to keep repainting the shadow. Since the shadow is also causing your transform problem, you should try to make the shadow you want in GIMP/Adobe or screenshot it in flutter, then add it to your project.
You should have an assets or images folder in your project directory, i.e, YOUR_FLUTTER_PROJECT/images. Put the shadow image in there.
Then, in the pubspec.yaml file, there should be a field for your assets. Add the path to the shadow file there, e.g.:
assets:
- images/a_dot_burr.jpeg
- images/a_dot_ham.jpeg
- images/YOUR_SHADOW_FILE
Run flutter pub get
In your code, replace your Container with this:
Image.asset('images/YOUR_SHADOW_FILE', height: 300, width: 200),
I haven't tested it, but I reckon it should still work.
I don't know the reasons behind it but removing the line ..setEntry(3, 2, 0.002) will remove the issues. However, there is a slight dimension issue during the animation which I thinks because of relativity. With the above line, it seems like animation decrease the blur effect with the increase of animation completion factor and reset to provided value when it reaches the starting point of animation.
I'm trying to replicate the following animation from dribble.com:
I've gotten the ScaleTransition to work but the SizeTransition does not. What am I doing wrong or what don't I understand?
When I only swap out the SizeTransition with a FadeTransition (and keep the same controllers & animations), the animations both run. When I move the Center widget from being a child of the SizeTransition to the parent the animation runs.
However it is not properly centered.
import 'package:flutter/material.dart';
class AnimatedCheck extends StatefulWidget {
#override
_AnimatedCheckState createState() => _AnimatedCheckState();
}
class _AnimatedCheckState extends State<AnimatedCheck> with TickerProviderStateMixin {
late AnimationController scaleController = AnimationController(duration: const Duration(milliseconds: 800), vsync: this);
late Animation<double> scaleAnimation = CurvedAnimation(parent: scaleController, curve: Curves.elasticOut);
late AnimationController checkController = AnimationController(duration: const Duration(milliseconds: 400), vsync: this);
late Animation<double> checkAnimation = CurvedAnimation(parent: checkController, curve: Curves.linear);
#override
void initState() {
super.initState();
scaleController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
checkController.forward();
}
});
scaleController.forward();
}
#override
void dispose() {
scaleController.dispose();
checkController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
double circleSize = 140;
double iconSize = 108;
return ScaleTransition(
scale: scaleAnimation,
child: Container(
height: circleSize,
width: circleSize,
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
),
child: SizeTransition(
sizeFactor: checkAnimation,
axis: Axis.horizontal,
axisAlignment: -1,
child: Center(
child: Icon(Icons.check, color: Colors.white, size: iconSize)
)
),
),
);
}
}
When you move the Center to the outside, it doesn't center the children of it's children, just puts it's child in the center of the area it occupies. Try setting the Container alignment using alignment: Alignment.center, inside of the Container. Please let me know if it doesn't work and I'll replicate the code to figure out the problem is.
Edit: This is because there is space around the visual check you see, the SizeTransition doesn't know this so it animates from the edge of the Icon which causes the visual bug you see. I'd recommend you use a tool like Rive (rive.app) to accomplish what you want, alternatively, you can use another animation or use some clunky workaround like animating the position while the size transition occurs so that it appears to be centered.
Hi if this is an issue for you, I figured out how both animations will be triggerd.
See code below.
Stack(
children: [
Center(
child: ScaleTransition(
scale: scaleAnimation,
child: Container(
height: circleSize,
width: circleSize,
decoration: BoxDecoration(
color: kApprovedColor,
shape: BoxShape.circle,
),
),
),
),
SizeTransition(
sizeFactor: checkAnimation,
axis: Axis.horizontal,
axisAlignment: -1,
child: Center(
child: Icon(Icons.check, color: Colors.white, size: iconSize),
),
),
],
),
Flutter's documentation has an explanation:
Like most widgets, SizeTransition will conform to the constraints it
is given, so be sure to put it in a context where it can change size.
For instance, if you place it into a Container with a fixed size, then
the SizeTransition will not be able to change size, and will appear to
do nothing.
Thank you. Now I know what I'm doing wrong.
How to create something like that in Flutter:
I tried the following code, but it's drawn without being animated.
CircularProgressIndicator(
value: 0.50,
backgroundColor: Colors.grey,
valueColor: AlwaysStoppedAnimation(Colors.pink),
)
You can use an ImplicityAnimatedWidget such as TweenAnimationBuilder
Example:
This will animate over 3.5 seconds and the progress will start from 0% to 100%, you can tweak those in the begin:, end: parameters
TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0.0, end: 1),
duration: const Duration(milliseconds: 3500),
builder: (context, value, _) => CircularProgressIndicator(value: value),
)
You can also use AnimatedBuilder to take more control over the animation
I want to make the same effect as this: https://api.flutter.dev/flutter/widgets/SizeTransition-class.html but starting from the beginning of an image. I tried everything and this does not work!
I tried to put Align in it, to put a container with the width modified by the value of the animation.. nothing works!
I have an animation before, and then it will call forward() on this one when it finishes (there is a function called complete that calls the forward() function).
initState() {
_sizeController =
AnimationController(duration: Duration(seconds: 1), vsync: this)
..addListener(() {
setState(() {});
});
_sizeAnimation = Tween(begin: 0.0, end: 27.0).animate(CurvedAnimation(
parent: _sizeController, curve: Curves.fastLinearToSlowEaseIn));
}
AnimatedContainer(
width: _width,
height: _height,
duration: Duration(milliseconds: 200),
decoration: BoxDecoration(
color: _color,
border: Border.all(
color: Color(0xFF707070), width: 2, style: BorderStyle.solid),
borderRadius: BorderRadius.circular(14.0),
),
child: SizeTransition(
sizeFactor: _sizeAnimation,
axis: Axis.horizontal,
axisAlignment: -1,
child:
Center(child: Image.asset('assets/images/check.png')),
),
Or it does nothing or it animates by scaling only.. How can i achieve the same effect as the example video on the widget page? I want that effect to happen showing a checkmark image inside a circle container. And before this the animatedcontainer will be a linear container that turns into the circle, and then the checkmark appears.
you need to call _sizeController.forward() to run the animation