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

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

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

本系列元件文章列表
1.NotificationListener2.Dismissible3.Switch
4.Scrollbar5.ClipPath6.CupertinoActivityIndicator
7.Opacity8.FadeTransition9. AnimatedOpacity
10. FadeInImage[本文]

一、認識 FadeInImage 元件

我們都知道,圖片無論是從資源、檔案、網路載入,都不會立刻完成,這樣會出現短暫的空白,尤其是網路圖片。自己處理預設佔點陣圖也比較麻煩。FadeInImage 的作用就是:在目標圖片載入完成前使用預設圖片佔位,載入完成後,目標圖片會漸變淡入,預設圖片會漸變淡出,這樣可以既解決圖片載入佔位問題,漸變的動畫在視覺上也不顯突兀。本文,就來全面介紹一下 FadeInImage 元件的使用以及簡單的原始碼實現。


1. FadeInImage 基本資訊

首先,它是一個 StatelessWidget,就說明它本身不會維護複雜的狀態類,只是在 build 方法中負責元件的構建。

在普通構造中,必須傳入兩個 ImageProvider 物件,image 表示待載入的目標圖片資源,placeholder 表示目標圖片載入過程中顯示的佔點陣圖片資源。另外還有很多用於配置圖片和動畫的屬性,後面再一一介紹。

final ImageProvider placeholder;
final ImageProvider image;
複製程式碼

2.FadeInImage 的簡單使用

只有知道兩個圖片資源就能最簡單地使用 FadeInImage,另外可以通過 widthheight 限制圖片的大小。下面頭像是使用網路圖片,黑色的是佔點陣圖,效果如下:

屬性名型別預設值用途
placeholderImageProviderrequired佔點陣圖片資源
imageImageProviderrequired目標圖片資源
widthdoublenull圖片寬
heightdoublenull圖片高
class FadeInImageDemo extends StatelessWidget{
  final headUrl =
      'https://sf1-ttcdn-tos.pstatp.com/img/user-avatar/5b2b7b85d1c818fa71d9e2e8ba944a44~300x300.image';
  @override
  Widget build(BuildContext context) {
    return FadeInImage(
      width: 100,
      height: 100,
      placeholder: AssetImage(
        'assets/images/default_icon.png',
      ),
      image: NetworkImage(headUrl),
    );
  }
}
複製程式碼

3.FadeInImage 動畫配置

淡出動畫 fadeOut 是針對佔點陣圖 而言的,淡入動畫 fadeIn 是針對目標圖 而言的,我們可以配置兩個動畫的時長和曲線來達到期望的動畫效果,如下是測試案例的效果:

屬性名型別預設值用途
fadeOutDurationDuration300 ms佔點陣圖淡出時長
fadeOutCurveCurvesCurves.easeOut佔點陣圖淡出動畫曲線
fadeInDurationDuration700 ms目標圖淡入時長
fadeInCurveCurvesCurves.easeIn目標圖淡入動畫曲線
FadeInImage(
  width: 100,
  height: 100,
  fadeOutDuration:Duration(seconds: 1),
  fadeOutCurve: Curves.easeOutQuad,
  fadeInDuration: Duration(seconds: 2),
  fadeInCurve: Curves.easeInQuad,
  placeholder: AssetImage(
    'assets/images/default_icon.png',
  ),
  image: NetworkImage(headUrl),
);
複製程式碼

4.FadeInImage 的圖片錯誤構建器

既然是圖片載入,就可能出錯,這兩個 XXXErrorBuilder 就是用來處理當圖片載入錯誤時應該如何顯示。如果不處理,就會像下面這樣:

我們可以指定 XXXErrorBuilder 回撥來構建錯誤時顯示的元件,如下當佔位符錯誤,顯示藍色 Container 示意一下,你可以指定任意的 Widget

屬性名型別預設值用途
placeholderErrorBuilderImageErrorWidgetBuildernull佔點陣圖載入錯誤時構建器
imageErrorBuilderImageErrorWidgetBuildernull目標圖載入錯誤時構建器
class FadeInImageDemo extends StatelessWidget{

  final headUrl =
      'https://sf1-ttcdn-tos.pstatp.com/img/user-avatar/5b2b7b85d1c818fa71d9e2e8ba944a44~300x300.image';

  @override
  Widget build(BuildContext context) {
    return
    FadeInImage(
      width: 100,
      height: 100,
      fadeOutDuration:Duration(seconds: 1),
      fadeOutCurve: Curves.easeOutQuad,
      fadeInDuration: Duration(seconds: 2),
      fadeInCurve: Curves.easeInQuad,
      placeholderErrorBuilder: _placeholderErrorBuilder,
      placeholder: AssetImage(
        'assets/images/default_icon2.png',
      ),
      image: NetworkImage(headUrl),
    );
  }

  Widget _placeholderErrorBuilder(BuildContext context, Object error, StackTrace? stackTrace) {
    return Container(
      width: 100,
      height: 100,
      color: Colors.blue,
    );
  }
}
複製程式碼

5.FadeInImage 其他屬性

剩下的幾個屬性都是傳給 Image 的,也就是說作用和 Image 中的屬性一致,這裡就不展開了。


6.FadeInImage 的其他構造

除了普通構造之外,FadeInImage 還有 assetNetworkmemoryNetwork ,這兩者只是佔位元件是 asset 路徑 還是 Uint8List 位元組陣列的區別。這兩個構造的目的是便於使用,可以指定縮放以及寬高。


可以看到兩個 ImageProvider 成員物件會通過 ResizeImage 進行處理,通過 ResizeImage 可以更改圖片資源的大小,通常用於減少 ImageCache 的記憶體佔用。

到這裡,FadeInImage 的使用方面就介紹完了。下面來看一下,作為一個 StatelessWidget , FadeInImage 為什麼可以執行這麼複雜的元件內容變化。


二、 FadeInImage 元件的原始碼實現

1. FadeInImage 元件的構建

對於 StatelessWidget 而言,邏輯基本上只在 build 方法中如何構建元件。如下是 FadeInImage#build,會通過 _image 方法建立 result 元件,並且一個 frameBuilder 的構建回撥,使用了 _AnimatedFadeOutFadeIn 元件。


如果 excludeFromSemantics=false 會套上一個語義元件,Semantics 。這就是 FadeInImage 構造的全部內容。


_image 方法就是根據入參和成員屬性構建 Image 元件而已,也沒什麼特別的。現在核心就是 frameBuilder 的回撥會構建 _AnimatedFadeOutFadeIn 。那 Image#frameBuilder 是什麼時候會呼叫呢?先讓子彈飛一會,現在看一下 _AnimatedFadeOutFadeIn 的實現。


2. _AnimatedFadeOutFadeIn 元件的實現

它繼承自 ImplicitlyAnimatedWidget ,表示其是一個 隱式動畫元件,在 AnimatedOpacity 一文中介紹過隱式元件的特性:外界只需要改變相關配置屬性,進重構元件就能觸發動畫,無需操作動畫控制器。

_AnimatedFadeOutFadeInState#build 中可以看出,淡入淡出的動畫實現是通過兩個 FadeTransition完成的,兩者通過 Stack 疊合。這樣看來是不是豁然開朗。


3. 漸變動畫如何觸發

AnimatedOpacity 一文中也說過,對於隱式元件,動畫的啟動是通過改變屬性和重建元件,來觸發 State#didUpdateWidget ,開啟動畫。

那問題來了,作為 StatelessWidgetFadeInImage ,如何重構 _AnimatedFadeOutFadeIn 。現在再來看 frameBuilder 就正是時候。Image 元件的 frameBuilder 是一個回撥的構建,它會在 _ImageState 構建時觸發。


第一次是圖片沒有載入:

第二次是圖片載入完成:

屬性變化 + 元件重構,從而觸發隱式元件的動畫啟動,完成需求。可以看出 FadeInImage 是非常巧妙的。FadeInImage 的使用方式到這裡就介紹完畢,那本文到這裡就結束了,謝謝觀看,明天見~

相關文章