在〈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 文件,變化組合上應該就不難了,來看一下效果: