我們可能會(huì)需要一些復(fù)雜的動(dòng)畫铅匹,這些動(dòng)畫可能由一個(gè)動(dòng)畫序列或重疊的動(dòng)畫組成,比如:有一個(gè)柱狀圖,需要在高度增長(zhǎng)的同時(shí)改變顏色汉规,等到增長(zhǎng)到最大高度后,我們需要在X軸上平移一段距離驹吮≌胧罚可以發(fā)現(xiàn)上述場(chǎng)景在不同階段包含了多種動(dòng)畫,要實(shí)現(xiàn)這種效果碟狞,使用交織動(dòng)畫(Stagger Animation)會(huì)非常簡(jiǎn)單啄枕。交織動(dòng)畫需要注意以下幾點(diǎn):
- 要?jiǎng)?chuàng)建交織動(dòng)畫,需要使用多個(gè)動(dòng)畫對(duì)象(
Animation
)族沃。 - 一個(gè)
AnimationController
控制所有的動(dòng)畫對(duì)象频祝。 - 給每一個(gè)動(dòng)畫對(duì)象指定時(shí)間間隔(Interval)(默認(rèn)情況下 時(shí)間間隔是0.0~1.0)
所有動(dòng)畫都由同一個(gè)AnimationController驅(qū)動(dòng)泌参,無論動(dòng)畫需要持續(xù)多長(zhǎng)時(shí)間,控制器的值必須在0.0到1.0之間常空,而每個(gè)動(dòng)畫的間隔(Interval)也必須介于0.0和1.0之間沽一。對(duì)于在間隔中設(shè)置動(dòng)畫的每個(gè)屬性,需要分別創(chuàng)建一個(gè)Tween用于指定該屬性的開始值和結(jié)束值漓糙。也就是說0.0到1.0代表整個(gè)動(dòng)畫過程铣缠,我們可以給不同動(dòng)畫指定不同的起始點(diǎn)和終止點(diǎn)來決定它們的開始時(shí)間和終止時(shí)間。
示例1
實(shí)現(xiàn)一個(gè)透明度變化昆禽、大小變化蝗蛙、顏色變化、旋轉(zhuǎn)的動(dòng)畫
class MSStaggerAnimationRouter1 extends StatefulWidget {
const MSStaggerAnimationRouter1({Key? key}) : super(key: key);
@override
State<MSStaggerAnimationRouter1> createState() =>
_MSStaggerAnimationRouter1State();
}
class _MSStaggerAnimationRouter1State extends State<MSStaggerAnimationRouter1>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> opacityAnimation;
late Animation<double> transformAnimation;
late Animation<double> sizeAnimation;
late Animation<Color?> colorAnimation;
@override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 5));
opacityAnimation = Tween(begin: 0.0, end: 1.0)
.animate(CurvedAnimation(parent: _controller, curve: Curves.linear));
transformAnimation = Tween(begin: 0.0, end: 2 * pi)
.animate(CurvedAnimation(parent: _controller, curve: Curves.linear));
sizeAnimation = Tween(begin: 0.0, end: 300.0)
.animate(CurvedAnimation(parent: _controller, curve: Curves.bounceIn));
colorAnimation = ColorTween(begin: Colors.amber, end: Colors.red).animate(
CurvedAnimation(parent: _controller, curve: Curves.decelerate));
_controller.forward();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Opacity(
opacity: opacityAnimation.value,
child: Transform(
transform: Matrix4.rotationZ(transformAnimation.value),
alignment: Alignment(0, 0), // 旋轉(zhuǎn)中心點(diǎn)
child: Container(
width: sizeAnimation.value,
height: sizeAnimation.value,
color: colorAnimation.value,
),
),
);
},
),
),
);
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
}
示例2
實(shí)現(xiàn)一個(gè)柱狀圖增長(zhǎng)的動(dòng)畫:
開始時(shí)高度從0增長(zhǎng)到300像素醉鳖,同時(shí)顏色由綠色漸變?yōu)榧t色捡硅;這個(gè)過程占據(jù)整個(gè)動(dòng)畫時(shí)間的60%。
高度增長(zhǎng)到300后辐棒,開始沿X軸向右平移100像素病曾;這個(gè)過程占用整個(gè)動(dòng)畫時(shí)間的40%。
class MSStaggerAnimationRouter2 extends StatefulWidget {
const MSStaggerAnimationRouter2({Key? key}) : super(key: key);
@override
State<MSStaggerAnimationRouter2> createState() =>
_MSStaggerAnimationRouter2State();
}
class _MSStaggerAnimationRouter2State extends State<MSStaggerAnimationRouter2>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> heightAnimation;
late Animation<Color?> colorAnimation;
late Animation<EdgeInsets?> paddingAnimation;
@override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 3));
// Interval 間隔漾根,前60%的動(dòng)畫時(shí)間
heightAnimation = Tween(begin: 0.0, end: 300.0).animate(CurvedAnimation(
parent: _controller, curve: Interval(0.0, 0.6, curve: Curves.linear)));
colorAnimation = ColorTween(begin: Colors.green, end: Colors.red).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.0, 0.6, curve: Curves.ease)));
// Interval 間隔泰涂,后40%的動(dòng)畫時(shí)間
paddingAnimation = Tween<EdgeInsets>(
begin: EdgeInsets.only(left: 0.0), end: EdgeInsets.only(left: 100))
.animate(
CurvedAnimation(parent: _controller, curve: Interval(0.6, 1.0)));
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
height: 300,
alignment: Alignment(0, 1),
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Padding(
padding: paddingAnimation.value!,
child: Container(
height: heightAnimation.value,
width: 50,
color: colorAnimation.value,
),
);
},
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.play_circle),
onPressed: () {
if (_controller.isAnimating) {
_controller.stop();
} else {
if (_controller.status == AnimationStatus.dismissed ||
_controller.status == AnimationStatus.forward) {
_controller.forward();
} else {
_controller.reverse();
}
}
},
),
);
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
}