preface
Looking through the portal of Wang Shu’s animation video tutorial recently, I can tell you that his explanation details are in place. Made notes by watching his Flutter animation to explain the chapter.
How to choose the right animation control
An implicit animation
Animated+WidgetName
Widget _buildAnimatedContainer() {
return Center(
child: AnimatedContainer(
alignment: Alignment.center,
duration: const Duration(milliseconds: 1000),
height: _height,
width: 200,
decoration: BoxDecoration(
boxShadow: const [BoxShadow(spreadRadius: 25, blurRadius: 25)],
borderRadius: BorderRadius.circular(150),
gradient: const LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [Colors.blue, Colors.white],
stops: [0.2.0.3],
),
),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 1000),
transitionBuilder: (child, animation) {
return ScaleTransition(
scale: animation,
child: FadeTransition(
opacity: animation,
child: child,
),
);
},
child: _height >= 500
? null
: Center(
key: ValueKey(_height),
child: Text(
"zhengzeqin $_height",
style: TextStyle(
fontSize: 18,
color: Colors.black,
),
),
),
),
),
);
}
Copy the code
AnimatedContainer
- Only properties under AnimatedContainer are involved in the animation changes; property changes in child’s widget are not
AnimatedSwitcher
- The AnimatedSwitcher component is used to perform the switching functions of animation components, such as zooming in on A and zooming in on B, and to cause animation when the child component key or component type changes (see key usage section).
- AnimatedSwitcher Child if equal to null will lose privacy, default FadeTransition gradient animation
- TransitionBuilder supports composing multiple animation components like ScaleTransition nested FadeTransition (similar to AnimatedCrossFade in and out)
Related components are
- AnimatedSwitcher
- AnimationPadding
- AnimatedOpacity
- AnimatedAlign
- .
AnimatedSwitcher(
duration: const Duration(milliseconds: 1000),
transitionBuilder: (child, animation) {
return ScaleTransition(
scale: animation,
child: FadeTransition(
opacity: animation,
child: child,
),
);
},
child: _height >= 500 ? null : Center(
key: ValueKey(_height),
child: Text(
"zhengzeqin $_height",
style: TextStyle(
fontSize: 18,
color: Colors.black,
),
),
),
)
Copy the code
Implicit animations have a curve
/// More animations and curves
/// Implicit animations have a curve curve. BounceOut, // the elastic end
/// The official document: https://api.flutter-io.cn/flutter/animation/Curves-class.html
Widget _buildAnimated() {
return Center(
child: AnimatedPadding(
curve: Curves.bounceOut, // Elastic end
duration: Duration(milliseconds: 1000),
padding: EdgeInsets.only(top: _height),
child: AnimatedOpacity (
curve: Curves.bounceInOut, // Elastic start and end
duration: Duration(milliseconds: 2000),
opacity: _opacity,
child: Container(
height: 300,
width: 300,
color: Colors.blue,
),
),
),
);
}
Copy the code
Keyframe animation Tween
- TweenAnimationBuilder
- Begin: 0.0, end: 1.0
- Note: The keyframe animation changes from the current value to the target value, such as setting 0 -> 100. If the current value is 10, it is from 10 -> 100
- Translation: the Transform. The translate
- Offset: offset (0,0) -> offset (-x, -x). It’s center to the bottom right
- Zoom: Transform scale
- Scale: 0.0 – > 1.0
- Rotation: Transform. Rotate
- Angle: 0.0 -> 6.28. Rotate a circle
/// Between, keyframe animation
Widget _buildTweenAnimated() {
return Center(
child: TweenAnimationBuilder(
duration: Duration(seconds: 1),
builder: (BuildContext context, double value, Widget? child) {
return Opacity(
opacity: value,
child: Container(
alignment: Alignment.center,
height: 300,
width: 300,
color: Colors.blue,
child: Transform.rotate(
angle: value * 6.28.// a 6.28 lap p is 3.14 1/2 laps
child: Text(
"zhengzeqin",
style: TextStyle(fontSize: 10 + 10 * value),
),
),
),
);
},
tween: Tween<double>(begin: 0.0, end: 1.0),),); }Copy the code
Example: flipped counters
- The flip is achieved by TweenAnimationBuilder keyframe animation combined with the maneuver of the position
/// Package counter
class TWAnimatedCounter extends StatelessWidget {
final Duration? duration;
final double fontSize;
final double count;
const TWAnimatedCounter({
Key? key,
this.duration,
this.fontSize = 100.this.count = 0,}) :super(key: key);
@override
Widget build(BuildContext context) {
return TweenAnimationBuilder(
duration: duration ?? const Duration(seconds: 1),
tween: Tween(end: count),
builder: (BuildContext context, double value, Widget? child) {
final whole = value ~/ 1; / / is rounded
final decimal = value - whole; / / get the decimal
return Stack(
alignment: Alignment.center,
children: [
Positioned(
top: -fontSize * decimal, / / 0 - > - 100
child: Opacity(
opacity: 1.0 - decimal, / / 1.0 - > 0.0
child: Text(
"$whole",
style: TextStyle(
fontSize: fontSize,
),
),
),
),
Positioned(
top: fontSize - decimal * fontSize, / / 100 - > 0
child: Opacity(
opacity: decimal, / / 0 - > 1.0
child: Text(
"${whole + 1}", style: TextStyle( fontSize: fontSize, ), ), ), ), ], ); }); }}Copy the code
According to the animation
WidgetName
+ Transition
SingleTickerProviderStateMixin
- Ticker is every time it refreshes. 60 Hz Triggers 60 times per second
AnimationController
- Reset: resets the recovery
- Stop: stop
- Forward: Executes the command once
- Repeat: Repeat the execution
- Reverse: reverse
- LowerBound -> upperBound defaults to 0 -> 1
Related components are
- RotationTransition
- FadeTransition
- ScaleTransition
- .
/// Inherit the Animation<double>
class AnimationController extends Animation<double> {
/ / ` ` `
}
_controller = AnimationController(
// upperBound: 10,
// lowerBound: 1,
vsync: this.// Vsync
duration: const Duration(milliseconds: 1000)); _controller.addListener(() {print("${_controller.value}");
});
/// Call setState
setState(() {
if (_isLoading) {
_controller.stop(); // reset: resets recovery stop: pauses
} else {
_controller.repeat(reverse: true); // forward: repeat: repeat} _isLoading = ! _isLoading; });Copy the code
/// Rotating animation
Widget _buildRotationTransition() {
return Center(
child: RotationTransition(
turns: _controller,
child: const Icon(
Icons.refresh,
size: 100,),),); }/// Opacity gradient animation
Widget _buildFadeTransition() {
return Center(
child: FadeTransition(
opacity: _controller, / / transparency
child: Container(
height: 100,
width: 100,
color: Colors.blue,
),
),
);
}
/// Zoom animation
Widget _buildScaleTransition() {
return Center(
child: ScaleTransition(
scale: _controller, // Scale multiple
child: Container(
height: 100,
width: 100,
color: Colors.yellow,
),
),
);
}
Copy the code
Keyframe animation Tween
- Through _controller. Drive (Tween (…). Add Tween keyframe start and end values.
- The equivalent is Tween(…) .animate(_controller)
- Chain superimposed with a CurveTween(Curve: Interval(0.8, 1.0)) means that the animation is not executed before 80% of the time, and the animation is completed in the remaining 20% of the time
- Chain adds a CurveTween(Curve: Curves).bounceInOut) means that the dynamic effect of adding an elastic in and out
- Note that the superposition of the animation is functionally similar: g(f(x))
- In the Slide Slide animation, offset is the origin of (0,0). An offset of 0.5 is a multiple of 0.5
Widget _buildTweenAnimation() {
return SlideTransition(
child: Container(
height: 100,
width: 100,
color: Colors.red,
),
position: Tween(
begin: const Offset(0.0),
end: const Offset(0.5.1),
)
.chain(
CurveTween(
curve: const Interval(0.8.1.0),// Curves.bounceOut
),
)
.animate(_controller),
// position: _controller.drive(
// Tween(
// begin: const Offset(0, 0),
// end: const Offset(0.5, 1),
/ /),
// ),
);
}
Copy the code
Case study: interlaced animation
/// Staggered animation
class TWSlidingBox extends StatelessWidget {
final AnimationController controller;
final Color color;
final Interval interval;
const TWSlidingBox({
Key? key,
required this.controller,
required this.color,
required this.interval,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SlideTransition(
child: Container(
width: 300,
height: 100,
color: color,
),
position: Tween(
begin: Offset.zero,
end: const Offset(0.1.0),
)
.chain(
CurveTween(curve: interval),
)
.chain(
CurveTween(curve: Curves.bounceInOut), // g(f(x))) .animate(controller), ); }}Copy the code
Custom animation
/// Custom animation
Widget _buildCustomAnimation() {
final Animation opacityAnimation = Tween(begin: 0.5, end: 0.8).animate(_controller);
final Animation heightAnimation = Tween(begin: 100.0, end: 200.0).animate(_controller);
return AnimatedBuilder(
animation: _controller,
child: const Text("Custom Animation",textAlign: TextAlign.center,), // This child is passed to the Builder for performance reasons
builder: (BuildContext context, Widget? child) {
return Opacity(
opacity: opacityAnimation.value,
child: Container(
alignment: Alignment.center,
color: Colors.blue,
width: 100, height: heightAnimation.value, child: child, ), ); }); }Copy the code
Case study: animation of 478 breathing method
- Note if you use multiple AnimationController requires with TickerProviderStateMixin, is SingleTickerProviderStateMixin under a single
- Leave the animation in wait by await future.delayed
void handleBreatedAnimation() async {
_expansionController.duration = const Duration(seconds: 4);
_expansionController.forward();
await Future.delayed(const Duration(seconds: 4));
_opacityController.duration = const Duration(milliseconds: 1750);
_opacityController.repeat(reverse: true);
await Future.delayed(const Duration(seconds: 7));
_opacityController.reset();
_expansionController.duration = const Duration(seconds: 8);
_expansionController.reverse();
}
Widget _buildBreatedAnimation() {
// _controller.duration = const Duration(seconds: 20);
// Animation animation1 = Tween(begin: 0.0, end: 1.0)
//. Chain (curve: const Interval(0.1, 0.2))
// .animate(_controller);
// Animation animation2 = Tween(begin: 1.0, end: 0.0)
//. Chain (curve: const Interval(0.4, 0.95))
// .animate(_controller);
return FadeTransition(
opacity: Tween(begin: 0.5, end: 1.0).animate(_opacityController),
child: AnimatedBuilder(
// animation: _controller,
animation: _expansionController,
builder: (BuildContext context, Widget? child) {
return Container(
width: 300,
height: 300,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.blue,
gradient: RadialGradient(
colors: [
Colors.blue[600]! , Colors.blue[100]! , ], stops: [ _expansionController.value, _expansionController.value +0.1[, (), (), (); },),); }Copy the code
conclusion
Animation. Xmind
reference
- Demo
- Uncle Wang is not bald – animation tutorial
- Official curve curvature
- How to make scrolling counter in flutter