前言:
這是我參與8月更文挑戰的第 9 天,活動詳情檢視:8月更文挑戰。為應掘金的八月更文挑戰
,我準備在本月挑選 31
個以前沒有介紹過的元件,進行全面分析和屬性介紹。這些文章將來會作為 Flutter 元件集錄
的重要素材。希望可以堅持下去,你的支援將是我最大的動力~
本系列 | 元件文章 | 列表 |
---|---|---|
1.NotificationListener | 2.Dismissible | 3.Switch |
4.Scrollbar | 5.ClipPath | 6.CupertinoActivityIndicator |
7.Opacity | 8.FadeTransition | 9. AnimatedOpacity [本文] |
一、認識 AnimatedOpacity 元件
上兩篇介紹了 Opacity 元件 和 FadeTransition 元件,他們都和操作元件的透明度有關。除了這兩位,還有一個元件也和透明度有關,它就是: AnimatedOpacity
。和 FadeTransition 元件的功能是一樣的,它也可以進行 透明度漸變動畫
。那他和 FadeTransition
有什麼異同點,為什麼框架中會給出兩個功能一致的元件?帶著這個問題,我們來開始認識 AnimatedOpacity
元件。
1.AnimatedOpacity 基本資訊
我們通過繼承樹可以看出,該元件繼承自 ImplicitlyAnimatedWidget
,是一個 StatefulWidget
。 ImplicitlyAnimatedWidget
稱之為 隱式動畫
,其最大的特點是: 使用者無需自己提供 動畫器
,也可以進行動畫變換。
通過 AnimatedOpacity
的構造入參,可以發現,它確實不需要傳入動畫器,但可以指定動畫相關的 時長
和 動畫曲線
。從這裡,很容易猜出 ImplicitlyAnimatedWidget
相關類會維護 動畫控制器
,封裝動畫的操作。這樣的目的很清楚:避免使用者直接和 動畫器
打交道,方便使用。從這裡可以衍生出一個問題 : 既然使用者無法直接操縱動畫器,那麼動畫是如何被開啟的?
帶著問題,繼續往下看。
2.AnimatedOpacity 的使用
我們先來看一個 AnimatedOpacity
使用的小 demo
。如下,通過 Switch
來切換 AnimatedOpacity
中 opacity
的值。可見,當 opacity
配置屬性變化時,就會執行動畫。
下面程式碼中,通過 Wrap
元件,豎直包裹 Switch
和 Container
,其中容器裡放著 AnimatedOpacity
,讓一個圖示進行動畫變化。在 Switch
點選時,重新構建 AnimatedOpacity
並更新 opacity
的配置值。然後就神奇地執行動畫了,可以看出,動畫的執行和元件重構是有關係的。
class AnimatedOpacityDemo extends StatefulWidget {
@override
_AnimatedOpacityDemoState createState() => _AnimatedOpacityDemoState();
}
class _AnimatedOpacityDemoState extends State<AnimatedOpacityDemo> {
final double beginOpacity = 1.0;
final double endOpacity = 0;
late double _opacity;
@override
void initState() {
super.initState();
_opacity = beginOpacity;
}
bool get selected => _opacity == 0;
@override
Widget build(BuildContext context) {
return Wrap(
direction: Axis.vertical,
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
Switch(
value: selected,
onChanged: onChanged,
),
Container(
color: Colors.grey.withAlpha(22),
width: 100,
height: 100,
child: buildAnimatedOpacity(),
),
],
);
}
Widget buildAnimatedOpacity() =>
AnimatedOpacity(
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
opacity: _opacity,
child: _buildChild(),
);
void onChanged(bool value) {
setState(() {
_opacity = value ? endOpacity : beginOpacity;
});
}
Widget _buildChild() =>
const Icon( Icons.add_to_drive, color: Colors.green, size: 60 );
}
複製程式碼
3.AnimatedOpacity 的價值
AnimatedOpacity
元件最大的亮點在於只要其 opacity
屬性發生變化,並重新構建,就可以進行動畫。下面的案例更能體現它的價值:通過 Slider
的滑動,控制 AnimatedOpacity
的 opacity
屬性變化,及重新構建。這樣每當滑動到新的值,都會 動畫漸變
到該透明度,如果使用 FadeTransition
元件,自己操作縱動畫器來實現,就會比較複雜。 AnimatedOpacity
元件這類的隱式動畫大大降低
了使用者使用動畫的門檻
。
// Slider 元件構建
Container(
height: 50,
child: Slider(
label: "$_opacity",
value: _opacity,
divisions: 5,
onChanged: onChanged,
),
),
void onChanged(double value) {
setState(() {
_opacity = value;
});
}
複製程式碼
另外,AnimatedOpacity
可以通過 onEnd
回撥監聽動畫執行完畢的時機。
三、 AnimatedOpacity 的原始碼實現
1. AnimatedOpacity 原始碼分析
前面說過 AnimatedOpacity
繼承自 ImplicitlyAnimatedWidget
。
而 ImplicitlyAnimatedWidget
最為 StatefulWidget
需要實現 createState
建立 State
物件,但由於其是抽象類,可以選擇不實現,交由子類完成。
ImplicitlyAnimatedWidget
中沒有實現 createState
,而把返回的狀態型別將限制為 ImplicitlyAnimatedWidgetState<ImplicitlyAnimatedWidget>
。
AnimatedOpacity
作為 ImplicitlyAnimatedWidget
子類,需要實現 createState
抽象方法。如下,狀態類為 _AnimatedOpacityState
。
這樣元件層面
的原始碼就理清了,ImplicitlyAnimatedWidget
相當於一箇中間層,可以通過 ImplicitlyAnimatedWidgetState
額外做一些事情。其子類元件的建立的狀態類,也需要繼承自 ImplicitlyAnimatedWidgetState
。下面就來看看,狀態類做了什麼。
2. 狀態類的處理
實現來看作為實現類的 _AnimatedOpacityState
。非常簡單,就是維護 _opacityAnimation
,依賴於 FadeTransition
元件進行動畫。是不是想直呼 好傢伙
。
動畫控制器的源泉在於抽象的狀態類 ImplicitlyAnimatedWidgetState
,這裡將進行 動畫控制器
的監聽、開啟等維護工作。
在 initState
中會對動畫器進行監聽,如果動畫完成,會執行 onEnd
回撥。
3. 動畫的開啟
看到這裡,你應該能猜出來動畫觸發的時機。當 StatefulWidget
重新構建時,狀態類是不會重新初始化的。而是觸發 State#didUpdateWidget
來通知 Widget
配置的變更,在此可以處理一下元件更新的邏輯。可以看出,在 ImplicitlyAnimatedWidgetState#didUpdateWidget
中,會對配置進行對比,發生變化將會更新。最後 _controller
會執行 forward
進行動畫。
AnimatedOpacity
元件,本質上就是對 動畫控制器
和 FadeTransition
元件的一層封裝。簡化使用者對動畫使用的門檻,降低動畫使用的錯誤率。其他的隱式動畫元件也是類似,AnimatedOpacity
的使用方式到這裡就介紹完畢,那本文到這裡就結束了,謝謝觀看,明天見~