前言:
這是我參與8月更文挑戰的第 10 天,活動詳情檢視:8月更文挑戰。為應掘金的八月更文挑戰
,我準備在本月挑選 31
個以前沒有介紹過的元件,進行全面分析和屬性介紹。這些文章將來會作為 Flutter 元件集錄
的重要素材。希望可以堅持下去,你的支援將是我最大的動力~
本系列 | 元件文章 | 列表 |
---|---|---|
1.NotificationListener | 2.Dismissible | 3.Switch |
4.Scrollbar | 5.ClipPath | 6.CupertinoActivityIndicator |
7.Opacity | 8.FadeTransition | 9. AnimatedOpacity |
10. FadeInImage[本文] |
一、認識 FadeInImage 元件
我們都知道,圖片無論是從資源、檔案、網路載入,都不會立刻完成,這樣會出現短暫的空白,尤其是網路圖片
。自己處理預設佔點陣圖也比較麻煩。FadeInImage
的作用就是:在目標圖片
載入完成前使用預設圖片
佔位,載入完成後,目標圖片
會漸變淡入,預設圖片
會漸變淡出,這樣可以既解決圖片載入佔位問題,漸變的動畫在視覺上也不顯突兀。本文,就來全面介紹一下 FadeInImage
元件的使用以及簡單的原始碼實現。
1. FadeInImage 基本資訊
首先,它是一個 StatelessWidget
,就說明它本身不會維護複雜的狀態類,只是在 build
方法中負責元件的構建。
在普通構造中,必須傳入兩個 ImageProvider
物件,image
表示待載入的目標圖片資源,placeholder
表示目標圖片載入過程中顯示的佔點陣圖片資源。另外還有很多用於配置圖片和動畫的屬性,後面再一一介紹。
final ImageProvider placeholder;
final ImageProvider image;
複製程式碼
2.FadeInImage 的簡單使用
只有知道兩個圖片資源就能最簡單地使用 FadeInImage
,另外可以通過 width
和 height
限制圖片的大小。下面頭像是使用網路圖片,黑色的是佔點陣圖,效果如下:
屬性名 | 型別 | 預設值 | 用途 |
---|---|---|---|
placeholder | ImageProvider | required | 佔點陣圖片資源 |
image | ImageProvider | required | 目標圖片資源 |
width | double | null | 圖片寬 |
height | double | null | 圖片高 |
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
是針對目標圖
而言的,我們可以配置兩個動畫的時長和曲線來達到期望的動畫效果,如下是測試案例的效果:
屬性名 | 型別 | 預設值 | 用途 |
---|---|---|---|
fadeOutDuration | Duration | 300 ms | 佔點陣圖淡出時長 |
fadeOutCurve | Curves | Curves.easeOut | 佔點陣圖淡出動畫曲線 |
fadeInDuration | Duration | 700 ms | 目標圖淡入時長 |
fadeInCurve | Curves | Curves.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
。
屬性名 | 型別 | 預設值 | 用途 |
---|---|---|---|
placeholderErrorBuilder | ImageErrorWidgetBuilder | null | 佔點陣圖載入錯誤時構建器 |
imageErrorBuilder | ImageErrorWidgetBuilder | null | 目標圖載入錯誤時構建器 |
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
還有 assetNetwork
和 memoryNetwork
,這兩者只是佔位元件是 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
,開啟動畫。
那問題來了,作為 StatelessWidget
的FadeInImage
,如何重構 _AnimatedFadeOutFadeIn
。現在再來看 frameBuilder
就正是時候。Image
元件的 frameBuilder
是一個回撥的構建,它會在 _ImageState
構建時觸發。
第一次是圖片沒有載入:
第二次是圖片載入完成:
屬性變化 + 元件重構,從而觸發隱式元件的動畫啟動,完成需求。可以看出 FadeInImage
是非常巧妙的。FadeInImage
的使用方式到這裡就介紹完畢,那本文到這裡就結束了,謝謝觀看,明天見~