在〈Assets 管理〉中,看過一些圖片的使用示範,如果你只是想載入某個來源的圖片,透過 Image.asset、Image.network、Image.file、Image.memory 之類的建構式,是最方便的方式,分別可以從 asset、網路、檔案、記憶體中進行圖片載入。
Image 是 StatefulWidget 的子類,也就是它本身是個 Widget,可以安排在 Widget 樹的任何位置,建構 Image 時必要的引數其實是 ImageProvider:
Image({Key key, @required ImageProvider image, ...)
ImageProvider 顧名思義,就是圖片的提供者,它是個抽象類別,中用過的 AssetImage 就是實作之一,其他還有 NetworkImage、FileImage、MemoryImage 等,Image.network、Image.file、Image.memory 就使用了這些類別的實例,建構 Image 時也可以自行指定 ImageProvider,這便於指定個別 ImageProvider 的細節,例如:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(
'openhome.cc'
),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Image(
image: NetworkImage('https://openhome.cc/Gossip/images/caterpillar.jpg', scale: 0.5),
width: 200,
height: 200,
fit: BoxFit.none,
color: Colors.red,
colorBlendMode: BlendMode.colorBurn,
),
),
Text('我是一隻弱小的毛毛蟲,想像有天可以成為強壯的挖土機,擁有挖掘夢想的神奇手套!')
],
),
),
)
);
NetworkImage 的第一個參數是 src,也就是指定網路圖片來源,scale 是縮放比例,要注意的是,範例中的 width、height 指定,並不是圖片本身的大小,而是圖片可繪製的區域大小。
嚴格說來,Image 只是個容器,不是圖片本身,也就是說 Image 只是個用來組合 ImageProvider、RawImage 等資源的容器,Image 透過 ImageProvider 取得圖片資料,而真正繪製圖片的是 RawImage,width、height、fit、color、colorBlendMode 等是提供給 RawImage 繪製時使用的資訊,實際上,Image 的 build 傳回的就是 RawImage:
...
@override
Widget build(BuildContext context) {
if (_lastException != null) {
assert(widget.errorBuilder != null);
return widget.errorBuilder(context, _lastException, _lastStack);
}
Widget result = RawImage(
image: _imageInfo?.image,
width: widget.width,
height: widget.height,
scale: _imageInfo?.scale ?? 1.0,
color: widget.color,
colorBlendMode: widget.colorBlendMode,
fit: widget.fit,
alignment: widget.alignment,
repeat: widget.repeat,
centerSlice: widget.centerSlice,
matchTextDirection: widget.matchTextDirection,
invertColors: _invertColors,
filterQuality: widget.filterQuality,
);
if (!widget.excludeFromSemantics) {
result = Semantics(
container: widget.semanticLabel != null,
image: true,
label: widget.semanticLabel ?? '',
child: result,
);
}
if (widget.frameBuilder != null)
result = widget.frameBuilder(context, result, _frameNumber, _wasSynchronouslyLoaded);
if (widget.loadingBuilder != null)
result = widget.loadingBuilder(context, result, _loadingProgress);
return result;
}
因此想知道 fit、color、colorBlendMode 等的作用,要查詢的是 RawImage 的 API 文件,fit 是填滿方式,color、colorBlendMode 表示指定的顏色與圖片要採用哪種混色演算,指定的顏色會逐像素地套用指定的演算法,來看一下執行結果:
也就是說,Flutter 中 XXXImage 命名的元件,並不見得是 Image 的子類,通常是表示它包含了圖片資源罷了,實際上會如何呈現圖片或展現特效,要看它是怎麼組合相關資源的。
例如 FadeInImage 是 StatelessWidget 的子類,只是 build 方法傳回 Image 實例,它可以指定大圖片載入前,先佔位顯示用的小圖,通常是在下載網路圖片時會用到,例如:
FadeInImage(
placeholder: AssetImage(...),
image: NetworkImage('https://openhome.cc/Gossip/images/caterpillar.jpg'),
)
另外還有 Ink.image,可以指定 ImageProvider,讓圖片在點選時,產生墨水渲染效果:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(
'openhome.cc'
),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Ink.image(
image: NetworkImage('https://openhome.cc/Gossip/images/caterpillar.jpg'),
width: 200,
height: 200,
child: InkWell(
onTap: () {}, // 必須有 onTap 才會有墨水渲染效果
)
),
),
Text('我是一隻弱小的毛毛蟲,想像有天可以成為強壯的挖土機,擁有挖掘夢想的神奇手套!')
],
),
),
)
);
只要認識 Image、ImageProvider、RawImage 之間基本的組合關係,再透過 API 文件,變化組合上應該就不難了,來看一下效果:


