前言
上一篇我們介紹了 Animation
和 AnimationController
的使用貌嫡,這是最基本的動畫構(gòu)建類比驻。但是,如果我們想構(gòu)建一個可復(fù)用的動畫組件岛抄,通過外部參數(shù)來控制其動畫效果的時候别惦,上一篇的方法就不太合適了。在 Flutter 中提供了 AnimatedWidget
組件用于構(gòu)建可復(fù)用的動畫組件夫椭。本篇我們用 AnimatedWidget
來實(shí)現(xiàn)組件的3D 旋轉(zhuǎn)效果掸掸,如下圖所示。
AnimatedWidget 簡介
AnimatedWidget
是一個抽象的 StatefulWidget
, 構(gòu)造方法如下所示扰付。
const AnimatedWidget({
Key? key,
required this.listenable,
}) : assert(listenable != null),
super(key: key);
主要在于接收一個 listenable
參數(shù)堤撵,通常會是 Animation
對象。在 AnimatedWidget
內(nèi)部的_AnimatedState
類中羽莺,會添加該對象變化監(jiān)聽回調(diào)实昨,進(jìn)而刷新界面。
class _AnimatedState extends State<AnimatedWidget> {
@override
void initState() {
super.initState();
widget.listenable.addListener(_handleChange);
}
@override
void didUpdateWidget(AnimatedWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.listenable != oldWidget.listenable) {
oldWidget.listenable.removeListener(_handleChange);
widget.listenable.addListener(_handleChange);
}
}
@override
void dispose() {
widget.listenable.removeListener(_handleChange);
super.dispose();
}
void _handleChange() {
setState(() {
// The listenable's state is our build state, and it changed already.
});
}
// ...
}
可以看到盐固,只需要將 Animation
對象傳給 AnimatedWidget
對象后荒给,就不需要我們之前那樣自己寫 addListener
之類的處理了。而整個動畫可以交給外部其他對象來控制刁卜,從而實(shí)現(xiàn)動畫組件的復(fù)用志电。
3D 旋轉(zhuǎn)動畫的實(shí)現(xiàn)
3D 旋轉(zhuǎn)的實(shí)現(xiàn)比較簡單,在 Container
組件有兩個參數(shù)控制轉(zhuǎn)換(transform)蛔趴,分別是:
-
transform
:Matrix4
對象挑辆,可以實(shí)現(xiàn)圍繞 X、Y孝情、Z軸的旋轉(zhuǎn)鱼蝉、平移,以及變形等效果咧叭。關(guān)于Matrix4
涉及到很多矩陣運(yùn)算和線性代數(shù)的知識蚀乔,可以參考 Matrix4的源碼自行溫習(xí)一下大學(xué)的數(shù)學(xué)知識??烁竭。 -
transformAlignment
:轉(zhuǎn)換的對齊方式菲茬,可以理解為起點(diǎn)位置,可以使用Alignment
對象來設(shè)置派撕。
有了這個基礎(chǔ)婉弹,我們就可以定義3D 旋轉(zhuǎn)動效了,我們定義一個通用的組件终吼,ThreeDAnimatedWidget
:
class ThreeDAnimatedWidget extends AnimatedWidget {
final Widget child;
const ThreeDAnimatedWidget(
{Key? key, required Animation<double> animation, required this.child})
: super(key: key, listenable: animation);
@override
Widget build(BuildContext context) {
final animation = listenable as Animation<double>;
return Center(
child: Container(
transform: Matrix4.identity()
..rotateY(2 * pi * animation.value)
..setEntry(1, 0, 0.01),
transformAlignment: Alignment.center,
child: child,
),
);
}
}
這里我們設(shè)置的是圍繞中心點(diǎn)繞 Y 軸旋轉(zhuǎn)镀赌,并使用 setEntry
設(shè)置了一定的傾斜角 (這會更有立體感)。實(shí)際我們也可以設(shè)置圍繞 X 軸或 Z 軸旋轉(zhuǎn)际跪。接下來就是這個動畫組件的應(yīng)用了商佛,我們構(gòu)建一個帶有陰影的文字(看起來像立體字)作為這個動畫的子組件,其他的控制和上一篇的是類似的姆打,完整代碼如下:
class AnimatedWidgetDemo extends StatefulWidget {
const AnimatedWidgetDemo({Key? key}) : super(key: key);
@override
_AnimatedWidgetDemoState createState() => _AnimatedWidgetDemoState();
}
class _AnimatedWidgetDemoState extends State<AnimatedWidgetDemo>
with SingleTickerProviderStateMixin {
late Animation<double> animation;
late AnimationController controller;
@override
void initState() {
super.initState();
controller =
AnimationController(duration: const Duration(seconds: 3), vsync: this);
animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('AnimatedWidget 動畫'),
),
body: ThreeDAnimatedWidget(
animation: animation,
child: Text(
'島上碼農(nóng)',
style: TextStyle(
fontSize: 42.0,
color: Colors.blue,
fontWeight: FontWeight.bold,
shadows: [
Shadow(
blurRadius: 2,
offset: Offset(2.0, 1.0),
color: Colors.blue[900]!),
],
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.play_arrow, color: Colors.white),
onPressed: () {
if (controller.status == AnimationStatus.completed) {
controller.reverse();
} else {
controller.forward();
}
},
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
可以看到良姆,這個 ThreeDAnimatedWidget
可以做到復(fù)用了,在需要這樣動效的場景里幔戏,按照上面的方式給它傳入 Animation
對象和子組件就可以了玛追。例如我們將文字修改為一張圖片。
//...
body: ThreeDAnimatedWidget(
animation: animation,
child: Image.asset(
'images/avatar.jpg',
width: 100,
height: 100,
),
),
//...
總結(jié)
本篇介紹了 AnimatedWidget
的使用,通過 AnimatedWidget
可以構(gòu)建可復(fù)用的動畫組件痊剖。同時韩玩,還通過 Container
的 transform
屬性加上 AnimatedWidget
實(shí)現(xiàn)了三維空間的旋轉(zhuǎn)效果。實(shí)際開發(fā)過程中陆馁,我們可以基于 AnimatedWidget
構(gòu)建很多個性化的找颓、可復(fù)用的動畫組件,提升應(yīng)用的趣味性叮贩。