Flutter animations are divided into the following three categories
- An implicit animation
- According to the animation
- Other animation
Animation control selection: what components do you want to implement an animation selection? If you want to achieve a cartoon animation (such as JINGdong pull-down refresh animation), you need to use third-party plug-ins (Rive/Flare, etc.) combined with the material given to us by the artist to achieve it. If it is a simple hand-drawn animation, you can use CustomPainter to complete the effect you want, which will be discussed later. Next, we will focus on implicit and display animations. In which scenarios are these two animations used? If you want to achieve a page-turning effect, control from hidden to display, control properties (width, height, color, transparency, position) change, you can use implicit animation; If the animation needs to loop or stop at any time, or if multiple controls need to animate cooperatively, use the AnimaterController in the display animation to do this.
An implicit animation
This article will focus on implicit animation (or fully automatic animation), the easiest animation to implement inside Flutter. A simple animation can be implemented in just a few lines of code. The control name is usually Animatedxxx. AnimatedContainer, AnimatedOpacity, AnimatedPadding, AnimatedCrossFade, AnimatedSwitcher, etc. If these do not meet your requirements, You can also make your own tween animations using TweenAnimationBuilder
1, AnimatedContainer
Here is a brief introduction to their usage, using AnimatedContainer as an example
AppBar: appBar (title: Text(' animation '),), body: Container(Child: Center(Child: AnimatedContainer(duration: Duration(seconds: 1), width: _width, height: 100, color: Colors.orange, ), ), ), floatingActionButton: FloatingActionButton( onPressed: (){ setState(() { _width+=50; }); }, child: Icon(Icons.add), ), )Copy the code
AnimatedContainer is basically the same as the normal Container property, but with two additional attributes: Duration (animation duration) and curve (default linear animation), where Duration must be entered, otherwise an error will be reported. Here, I only change its width. In fact, all attributes of the Container can be animated.
AnimatedContainer(
duration: Duration(seconds: 1),
width: _width,
height: _height,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(_change ? 0 : _width/2)),
border: Border.all(color:_change ? Colors.red : Colors.orange, width: _change ? 0 : 20),
gradient: LinearGradient(colors: [Colors.red, Colors.orange]),
boxShadow: [
BoxShadow(spreadRadius: _change ? 0 : 10, blurRadius: _change ? 0 : 15)
]
),
)
Copy the code
I didn’t think of any good animation here, just casually get a few attributes for your reference. Curve defaults to linear (Curves. Linear), and other attributes can be set. This article introduces the effects of each value of curve
AnimatedOpacity: controls display and opacity
child: Center( child: AnimatedOpacity( duration: Duration(seconds: 1), opacity: _opacity ? 0:1.0, child: Container(width: 100, height: 100, color: color.orange,),),)Copy the code
3, AnimatedSwitcher
Animation of two widgets as they switch
Center( child: AnimatedSwitcher( duration: Duration(seconds: 1), child: _change ? Container(width: 200, height: 200, color: Colors.orange) : Image.network( 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2Fmonth_1011%2F1011250123f7480cd63703 C992.jpg&refer=http%3A%2F%2Fattach.bbs.miui.com & app = 2002 & size = f9999, 10000 & q = a80 & n = 0 & g = 0 n & FMT = jpeg? = 1620601261 & t = a58b0 the SEC f0f98e0eb74854c304fa118dcbf', width: 200, height: 200), ), ),Copy the code
AnimatedSwitcher has one more attribute than the other Animatedxxx Widgets: As you can see from the transitionBuilder, the two widgets are a hidden animation, and the animation is a FadeTransition if you go to the source code
We can also use the desired transform:
Instead of using a zoom effect, what if you want both a zoom effect and transparency from 0 to 1? This can actually be nested:
Some of you might have this situation when you’re animating your Text, so I’ve put the Text in the AnimatedSwitcher, and there’s no animation when the Text changes
In this case, we need to talk about the update mechanism of a Flutter. The Flutter will compare the runtimeType of the Widget with the runtimeType of the Text on each refresh. The Flutter thinks that the child element has not changed, so the state has not changed. We can add a key to let Flutter know that the Text Widget changes every time Flutter refreshes:
Now the Text animation is back. If we look at the AnimatedSwitcher source code, we can also see a layoutBuilder property, as the name indicates, which should be used to layout the Child. By default, we use a Stack to wrap our child. From this we can also guess that when the animation happens, Flutter creates a new child for us. During the animation switch, both the new child and the old one exist. After the animation ends, the old one is hidden, leaving only the new one
Then we refer to his source code to write a layout of their own:
4, AnimatedCrossFade
This Widget is also used for switching and is also used to fade in and out
Center( child: AnimatedCrossFade( firstChild: Container(width: 100, height: 100, color: Colors.orange), secondChild: Image.network('https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2Fmonth_1011%2F10112501 23 f7480cd63703c992.jpg&refer=http%3a%2f%2fattach.bbs.miui.com & app = 2002 & size = f9999, 10000 & q = a80 & n = 0 & g = 0 n & FMT = jpeg? The SEC = 1620 601261&t=a58b0f0f98e0eb74854c304fa118dcbf', width: 100,), duration: Duration(seconds: 1), crossFadeState: _change ? CrossFadeState.showFirst : CrossFadeState.showSecond, ), ),Copy the code
Pay attention to
The other Animatedxxx widgets are used in a similar way, but it is important to note that the AnimatedContainer animates only its own property, not its child.
child: Center(
child: AnimatedContainer(
duration: Duration(seconds: 1),
child: Container(
width: _width,
height: 100,
color: Colors.blue,
),
),
),
)
Copy the code
In this case, there is an extra child in the AnimatedContainer and the changing width is added to the child, so there is no animation.
5, TweenAnimationBuilder
TweenAnimationBuilder can customize the animation we want, we can not use the previous mentioned AnimatedContainer/AnimatedPadding Widget, such as direct use of the Container/Padding to achieve animation, Let’s start with a simple animation
TweenAnimationBuilder several properties for the duration of animation time, must pass, do not pass this parameter complains, tween between English meaning is XXX, between two values, the incoming of the two values is not only a double, also can be Color, Offset, etc., Tween
(begin: 10.0, end: _end) I stole the code above by not specifying a type, but if begin passes 10, it will return an error because width is a double and begin is an int. We should see more of the Builder parameter here. Normally we do something here, where the Flutter renders every frame and returns the values between begin and end to us. We get these values and assign them to the Widget. Then we assign width to the Container and see that the Container width changes from 10.0 to 200.0. And then there’s a child, what does that child do? Because we only returned a simple Container in Builder and didn’t use a cumbersome layout, let’s say we had code like this:
Center(Child: TweenAnimationBuilder(duration: duration (seconds: 1), tween: tween <double>(begin: 50.0, end: _end), builder: (BuildContext context, value, child) { return Container( width: value, height: 600, color: Colors.orange, child: Container( padding: EdgeInsets.all(10), child: Column( children: List.generate( 30, (index) => Text(index.toString(), style: TextStyle(fontSize: 15)))))); },),)Copy the code
It’s the outer Container that does the animation change. The inner Container doesn’t change, so we can take the inner Container outside as the Child property of the TweenAnimationBuilder, and then pass it to the Child in the Builder. Here it is:
TweenAnimationBuilder(duration: duration (seconds: 1), tween: tween <double>(begin: 50.0, end: _end), Builder: (BuildContext context, value, child) { return Container( width: value, height: 600, color: Colors.orange, child:child ); }, child: Container( padding: EdgeInsets.all(10), child: Column( children: List.generate( 30, (index) => Text(index.toString(), style: TextStyle(fontSize: 15))))), )Copy the code
Because the Builder function is called every render frame, and the outer layer of the child is unchanged, can be directly taken over to use, so as to save performance to a certain extent.
Finally, we used the changed value of the Flutter return in the Builder, but we did not call the setState that we normally use. This was because a listener inside the Flutter called the setState for me.