前言:
這是我參與8月更文挑戰的第 15 天,活動詳情檢視:8月更文挑戰。為應掘金的八月更文挑戰
,我準備在本月挑選 31
個以前沒有介紹過的元件,進行全面分析和屬性介紹。這些文章將來會作為 Flutter 元件集錄
的重要素材。希望可以堅持下去,你的支援將是我最大的動力~
一、認識 AnimatedContainer 元件
在 Container 元件 一文中,我們知道它存在的價值是:整合如下 8 個單子元件,這樣通過一個 Container
完成多種功能。可以避免在使用是層層巢狀,簡化程式碼結構。而 AnimatedContainer
就相當於一個加強版的 Container
,可以讓其中的各個屬性在變化時具有動畫效果
。
1.AnimatedContainer 基本資訊
AnimatedContainer
是一個隱式動畫
元件,和之前介紹過的 AnimatedOpacity 是同類,這種動畫元件,只需要更改屬性
+ 重新構建
就可以實現動畫。這類的動畫元件,都有一些共同的屬性,如 duration
表示動畫時長、curve
表示動畫曲線、onEnd
表示動畫結束的回撥。
下面可以對比一下 AnimatedContainer
和 Container
的屬性,可以看出基本是一模一樣的。也就是說了解 Container
屬性的用法之後,其實 AnimatedContainer
自然也就會了。兩者的區別只在於:Container
在屬性變化重構後,是直接變換,而 AnimatedContainer
是動畫漸變。
2. AnimatedContainer 元件的使用
我們先通過一個簡單的例子看一下 AnimatedContainer
的使用方式。如下,當點選按鈕時,通過 _changeSize
方法改變寬高數值,並重建元件。可以看出 AnimatedContainer
尺寸變化會有動畫效果。想一下,如果這裡使用 Container
元件,那麼將會直接改變到對應數值,就比較生硬。
class AnimatedContainerDemo extends StatefulWidget {
@override
_AnimatedContainerDemoState createState() => _AnimatedContainerDemoState();
}
class _AnimatedContainerDemoState extends State<AnimatedContainerDemo> {
double _width = 180;
double _height = 120;
@override
Widget build(BuildContext context) {
return Wrap(
direction: Axis.vertical,
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
ElevatedButton(
child: const Text('更新寬高'),
onPressed: _changeSize,
),
const SizedBox(height: 10,),
buildAnimatedContainer()
],
);
}
Widget buildAnimatedContainer() => AnimatedContainer(
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
height: _height,
color: Colors.black12,
width: _width,
onEnd: onEnd,
);
void onEnd() {
print('End');
}
void _changeSize() {
setState(() {
_width = _width == 100 ? 180 : 100;
_height = _height == 100 ? 120 : 100;
});
}
}
複製程式碼
3.AnimatedContainer 元件的其他屬性
AnimatedContainer
的其他某些屬性也可以進行動畫,比如下面的 alignment
和 color
。和寬高一樣,只需要改變屬性值
和重構元件
,就能進行動畫。不需要處理動畫器,這就是隱式動畫的方便之處。
Alignment _alignment = Alignment.topLeft;
Color _color = Colors.orange;
Widget buildAnimatedContainer() => AnimatedContainer(
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
height: 100,
color: _color.withOpacity(0.2),
width: 100,
alignment: _alignment,
onEnd: onEnd,
child: FlutterLogo(),
);
void _change() {
setState(() {
_alignment =
_alignment == Alignment.center ?
Alignment.topLeft : Alignment.center;
_color = _color == Colors.orange ?
Colors.purple : Colors.orange;
});
}
複製程式碼
我們也可以對 decoration
屬性進行動畫,如下的圓角和陰影裝飾,也是隻需要改變屬性值
和重構元件
即可。
總的來說 AnimatedContainer
的屬性意義和 Container
一模一樣,只是前者在屬性變化重構時
會進行動畫過渡到該值。這樣會使變化顯得不那麼突兀,視覺上更好些。其他的屬性參考 Container 元件 一文,大家可以自己試試改變這些屬性的效果。
二、AnimatedContainer 的原始碼實現
AnimatedContainer
繼承自 ImplicitlyAnimatedWidget
,這也就說明它和 AnimatedOpacity 是同族的,所以他們在原始碼實現上是類似的。
不同點在於AnimatedOpacity
是通過 FadeTransition
元件實現的動畫漸變功能,該元件天生可以監聽 Listenable
物件觸發重繪。而 _AnimatedContainerState
繼承自 AnimatedWidgetBaseState
。
AnimatedWidgetBaseState
中會監聽動畫控制器 controller
,通過 setState
對子元件進行 區域性更新
。其原理和 AnimatedBuilder
是一致的。
從狀態類中維護的 XXXTween
可以看出能夠進行動畫的屬性有哪些。從元件的構建中可以看出,本身還是使用了 Container
實現的。由於之前監聽了動畫,並執行setState
,那麼在動畫的每一幀,都會更新 Container
的屬性配置資訊,進行區域性更新
。
最後,動畫的開啟和 AnimatedOpacity 一文中介紹的一樣,比較他們都是 ImplicitlyAnimatedWidget
。動畫器的維護都封裝在 ImplicitlyAnimatedWidgetState
中:
當 StatefulWidget
重新構建時,狀態類是不會重新初始化的。而是觸發 State#didUpdateWidget
來通知 Widget
配置的變更,在此可以處理一下元件更新的邏輯。可以看出,如下在 didUpdateWidget
中,會對配置進行對比,發生變化將會更新。最後 _controller
會執行 forward
進行動畫。
那AnimatedContainer
的使用方式到這裡就介紹完畢,那本文到這裡就結束了,謝謝觀看,明天見~