【Flutter 元件集錄】FadeTransition| 8月更文挑戰

張風捷特烈發表於2021-08-08
前言:

這是我參與8月更文挑戰的第 8 天,活動詳情檢視:8月更文挑戰。為應掘金的八月更文挑戰,我準備在本月挑選 31 個以前沒有介紹過的元件,進行全面分析和屬性介紹。這些文章將來會作為 Flutter 元件集錄 的重要素材。希望可以堅持下去,你的支援將是我最大的動力~


一、認識 FadeTransition 元件

上一篇介紹了 Opacity 元件,今天來看一個可以透明動畫變換的元件: FadeTransition。其作用是:將一個元件 以指定透明度 opacity 動畫進行透明變化`。


1.FadeTransition 基本資訊

下面是 FadeTransition 元件類的定義構造方法,可以看出它繼承自 SingleChildRenderObjectWidget。例項化時必須傳入 opacity 入參,其型別為 Animation<double> ,用於控制透明度的動畫器。還可以傳入一個 chuild 元件。

---->[FadeTransition#FadeTransition 宣告]----
final Animation<double> opacity;
複製程式碼

2.FadeTransition 的使用

FadeTransition 元件的比 Opacity 複雜很多,因為我們要指定 opacity 動畫器,像這樣由使用者知道動畫器 實現動畫效果的,稱之為 顯示動畫元件 。如下程式碼,是在 2S 內將透明度在 0.2 ~ 1.0 間變換的動畫效果:

由於需要使用 動畫器,我們需要使用 StatefulWidget ,在 XXXState 中混入 SingleTickerProviderStateMixin ,可以讓狀態類作為 vsync 用來建立 AnimationController 。在 dispose 中釋放動畫控制器。

class FadeTransitionDemo extends StatefulWidget {
  @override
  _FadeTransitionDemoState createState() => _FadeTransitionDemoState();
}

class _FadeTransitionDemoState extends State<FadeTransitionDemo>
    with SingleTickerProviderStateMixin {
  late AnimationController _ctrl;
  late Animation<double> opacityAnim;

  @override
  void initState() {
    super.initState();
    _ctrl = AnimationController(vsync: this, duration: const Duration(seconds: 2));
    opacityAnim= Tween<double>(begin: 0.2,end: 1.0).animate(_ctrl);
    _ctrl..forward();
  }

  @override
  void dispose() {
    _ctrl.dispose();
    super.dispose();
  }
複製程式碼

通過 Tween_ctrl 建立一個 0.2 ~ 1.0 的動畫器 opacityAnim , 作為入參傳入 FadeTransition 建構函式中。這樣在 _ctrl 動畫控制器開啟時,其子元件就可以執行透明度漸變動畫。

@override
Widget build(BuildContext context) {
  return GestureDetector(
    onTap: () {
      _ctrl.forward(from: 0);
    },
    child: FadeTransition(
      opacity: opacityAnim,
      child: Image.asset(
        'assets/images/icon_head.png',
        width: 100,
        height: 100,
      ),
    ),
  );
}
複製程式碼

二、 FadeTransition 的原始碼實現

1. FadeTransition 原始碼分析

它繼承自 SingleChildRenderObjectWidget 就說明,該元件需要維護一個 RenderObject 物件的建立及更新。

createRenderObject 方法中,建立 RenderAnimatedOpacityopacity 動畫器會被傳如構造入參中。在 updateRenderObject 中,對 RenderAnimatedOpacity 物件進行更新。也就是說,漸變透明變換的繪製處理是在 RenderAnimatedOpacity 中進行的。


2.RenderAnimatedOpacity 原始碼分析

對於 FadeTransition 元件來說,最神奇的應該是:為什麼透明度會跟隨 Animation 物件不斷觸發重繪,從而進行動畫。既然 動畫器 opacity 是一個 Listenable 物件,那很容易想到是通過監聽 動畫器 進行重繪。 RenderAnimatedOpacity 通過混入 RenderAnimatedOpacityMixin 實現動畫效果。


RenderAnimatedOpacityMixin#attach 方法中,會通過 addListener 來監聽動畫器的變化。在 detach 中移除監聽。監聽的方法是 _updateOpacity

_updateOpacity 方法中,如果新舊的 alpha 值不同,就會觸發 markNeedsPaint 進行通知重繪。


RenderAnimatedOpacityMixin#paint 方法中的繪製邏輯和 Opacity 元件繪製是一樣的。當 child 非空時,如果 _alpha = 0 就什麼都不需要畫,直接返回。如果 _alpha = 255 ,則直接繪製 child

如果有透明度時,會通過 context.pushOpacity ,建立一個透明層 layer 來完成透明功能。該方法在 Opacity 元件一文中介紹過了,這裡不再贅述。


3. FadeTransition 的價值

如果不知道 FadeTransition 元件的存在,我們想要實現 透明度漸變 的效果,能想到的可能就是通過 AnimatedBuilder 監聽 Opacity 元件,來動態改變透明度值,完成動畫,程式碼如下:

AnimatedBuilder(
  animation: opacityAnim,
  builder: (ctx, child) => Opacity(
    opacity: opacityAnim.value,
    child: child,
  ),
  child: Image.asset(
    'assets/images/icon_head.png',
    width: 100,
    height: 100,
  ),
),
複製程式碼

上面的方式可以達到一樣的效果,那這和 FadeTransition 想必有什麼劣勢呢?首先,很明顯使用 AnimatedBuilder 元件比較麻煩;其次使用 AnimatedBuilder 元件,每次動畫器數值變化都會執行 builder 回撥來建立元件,也就是說 Opacity 元件會被建立很多次。

而從 FadeTransition 原始碼中可以看出,對動畫器的監聽是在其對應的 RenderAnimatedOpacity 中進行的,也就是說,通過 FadeTransition 元件進行 透明度漸變動畫 的整個動畫過程,是沒有伴隨任何元件重建的。這就是其最大的優勢。

FadeTransition 元件 的使用方式到這裡就介紹完畢,那本文到這裡就結束了,謝謝觀看,明天見~

相關文章