Flutter 中,我們可以通過Image
組件來加載并顯示圖片,Image
的數(shù)據(jù)源可以是 asset、文件、內(nèi)存以及網(wǎng)絡(luò)。
ImageProvider
是一個(gè)抽象類,主要定義了圖片數(shù)據(jù)獲取的接口load()
,從不同的數(shù)據(jù)源獲取圖片需要實(shí)現(xiàn)不同的ImageProvider
,如AssetImage
是實(shí)現(xiàn)了從 Asset 中加載圖片的 ImageProvider,而NetworkImage
實(shí)現(xiàn)了從網(wǎng)絡(luò)加載圖片的 ImageProvider。
Image
widget 有一個(gè)必選的image
參數(shù),它對(duì)應(yīng)一個(gè) ImageProvider。下面我們分別演示一下如何從 asset 和網(wǎng)絡(luò)加載圖片。
images目錄
,并將圖片 avatar.png 拷貝到該目錄。pubspec.yaml
中的flutter
部分添加如下內(nèi)容: assets:
- images/avatar.png
注意: 由于 yaml 文件對(duì)縮進(jìn)嚴(yán)格,所以必須嚴(yán)格按照每一層兩個(gè)空格的方式進(jìn)行縮進(jìn),此處assets前面應(yīng)有兩個(gè)空格。
Image(
image: AssetImage("images/avatar.png"),
width: 100.0
);
Image 也提供了一個(gè)快捷的構(gòu)造函數(shù)Image.asset
用于從 asset 中加載、顯示圖片:
Image.asset("images/avatar.png",
width: 100.0,
)
Image(
image: NetworkImage(
"https://avatars2.githubusercontent.com/u/20411648?s=460&v=4"),
width: 100.0,
)
Image 也提供了一個(gè)快捷的構(gòu)造函數(shù)Image.network
用于從網(wǎng)絡(luò)加載、顯示圖片:
Image.network(
"https://avatars2.githubusercontent.com/u/20411648?s=460&v=4",
width: 100.0,
)
運(yùn)行上面兩個(gè)示例,圖片加載成功后如圖3-17所示:
Image
在顯示圖片時(shí)定義了一系列參數(shù),通過這些參數(shù)我們可以控制圖片的顯示外觀、大小、混合效果等。我們看一下 Image 的主要參數(shù):
const Image({
...
this.width, //圖片的寬
this.height, //圖片高度
this.color, //圖片的混合色值
this.colorBlendMode, //混合模式
this.fit,//縮放模式
this.alignment = Alignment.center, //對(duì)齊方式
this.repeat = ImageRepeat.noRepeat, //重復(fù)方式
...
})
width
、height
:用于設(shè)置圖片的寬、高,當(dāng)不指定寬高時(shí),圖片會(huì)根據(jù)當(dāng)前父容器的限制,盡可能的顯示其原始大小,如果只設(shè)置width
、height
的其中一個(gè),那么另一個(gè)屬性默認(rèn)會(huì)按比例縮放,但可以通過下面介紹的fit
屬性來指定適應(yīng)規(guī)則。fit
:該屬性用于在圖片的顯示空間和圖片本身大小不同時(shí)指定圖片的適應(yīng)模式。適應(yīng)模式是在BoxFit
中定義,它是一個(gè)枚舉類型,有如下值:fill
:會(huì)拉伸填充滿顯示空間,圖片本身長(zhǎng)寬比會(huì)發(fā)生變化,圖片會(huì)變形。cover
:會(huì)按圖片的長(zhǎng)寬比放大后居中填滿顯示空間,圖片不會(huì)變形,超出顯示空間部分會(huì)被剪裁。contain
:這是圖片的默認(rèn)適應(yīng)規(guī)則,圖片會(huì)在保證圖片本身長(zhǎng)寬比不變的情況下縮放以適應(yīng)當(dāng)前顯示空間,圖片不會(huì)變形。fitWidth
:圖片的寬度會(huì)縮放到顯示空間的寬度,高度會(huì)按比例縮放,然后居中顯示,圖片不會(huì)變形,超出顯示空間部分會(huì)被剪裁。fitHeight
:圖片的高度會(huì)縮放到顯示空間的高度,寬度會(huì)按比例縮放,然后居中顯示,圖片不會(huì)變形,超出顯示空間部分會(huì)被剪裁。none
:圖片沒有適應(yīng)策略,會(huì)在顯示空間內(nèi)顯示圖片,如果圖片比顯示空間大,則顯示空間只會(huì)顯示圖片中間部分。
一圖勝萬言! 我們對(duì)一個(gè)寬高相同的頭像圖片應(yīng)用不同的fit
值,效果如圖3-18所示:
color
和 colorBlendMode
:在圖片繪制時(shí)可以對(duì)每一個(gè)像素進(jìn)行顏色混合處理,color
指定混合色,而colorBlendMode
指定混合模式,下面是一個(gè)簡(jiǎn)單的示例: Image(
image: AssetImage("images/avatar.png"),
width: 100.0,
color: Colors.blue,
colorBlendMode: BlendMode.difference,
);
運(yùn)行效果如圖3-19所示(彩色):
repeat
:當(dāng)圖片本身大小小于顯示空間時(shí),指定圖片的重復(fù)規(guī)則。簡(jiǎn)單示例如下: Image(
image: AssetImage("images/avatar.png"),
width: 100.0,
height: 200.0,
repeat: ImageRepeat.repeatY ,
)
運(yùn)行后效果如圖3-20所示:
完整的示例代碼如下:
import 'package:flutter/material.dart';
class ImageAndIconRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
var img=AssetImage("imgs/avatar.png");
return SingleChildScrollView(
child: Column(
children: <Image>[
Image(
image: img,
height: 50.0,
width: 100.0,
fit: BoxFit.fill,
),
Image(
image: img,
height: 50,
width: 50.0,
fit: BoxFit.contain,
),
Image(
image: img,
width: 100.0,
height: 50.0,
fit: BoxFit.cover,
),
Image(
image: img,
width: 100.0,
height: 50.0,
fit: BoxFit.fitWidth,
),
Image(
image: img,
width: 100.0,
height: 50.0,
fit: BoxFit.fitHeight,
),
Image(
image: img,
width: 100.0,
height: 50.0,
fit: BoxFit.scaleDown,
),
Image(
image: img,
height: 50.0,
width: 100.0,
fit: BoxFit.none,
),
Image(
image: img,
width: 100.0,
color: Colors.blue,
colorBlendMode: BlendMode.difference,
fit: BoxFit.fill,
),
Image(
image: img,
width: 100.0,
height: 200.0,
repeat: ImageRepeat.repeatY ,
)
].map((e){
return Row(
children: <Widget>[
Padding(
padding: EdgeInsets.all(16.0),
child: SizedBox(
width: 100,
child: e,
),
),
Text(e.fit.toString())
],
);
}).toList()
),
);
}
}
Flutter 框架對(duì)加載過的圖片是有緩存的(內(nèi)存),默認(rèn)最大緩存數(shù)量是1000,最大緩存空間為 100M。關(guān)于 Image 的詳細(xì)內(nèi)容及原理我們將會(huì)在后面進(jìn)階部分深入介紹。
Flutter 中,可以像Web開發(fā)一樣使用 iconfont,iconfont 即“字體圖標(biāo)”,它是將圖標(biāo)做成字體文件,然后通過指定不同的字符而顯示不同的圖片。
在字體文件中,每一個(gè)字符都對(duì)應(yīng)一個(gè)位碼,而每一個(gè)位碼對(duì)應(yīng)一個(gè)顯示字形,不同的字體就是指字形不同,即字符對(duì)應(yīng)的字形是不同的。而在 iconfont 中,只是將位碼對(duì)應(yīng)的字形做成了圖標(biāo),所以不同的字符最終就會(huì)渲染成不同的圖標(biāo)。
在 Flutter 開發(fā)中,iconfont 和圖片相比有如下優(yōu)勢(shì):
Flutter 默認(rèn)包含了一套 Material Design 的字體圖標(biāo),在pubspec.yaml
文件中的配置如下
flutter:
uses-material-design: true
Material Design 所有圖標(biāo)可以在其官網(wǎng)查看:https://material.io/tools/icons/
我們看一個(gè)簡(jiǎn)單的例子:
String icons = "";
// accessible: or 0xE914 or E914
icons += "\uE914";
// error: or 0xE000 or E000
icons += " \uE000";
// fingerprint: or 0xE90D or E90D
icons += " \uE90D";
Text(icons,
style: TextStyle(
fontFamily: "MaterialIcons",
fontSize: 24.0,
color: Colors.green
),
);
運(yùn)行效果如圖3-21所示:
通過這個(gè)示例可以看到,使用圖標(biāo)就像使用文本一樣,但是這種方式需要我們提供每個(gè)圖標(biāo)的碼點(diǎn),這并對(duì)開發(fā)者不友好,所以,F(xiàn)lutter 封裝了IconData
和Icon
來專門顯示字體圖標(biāo),上面的例子也可以用如下方式實(shí)現(xiàn):
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.accessible,color: Colors.green,),
Icon(Icons.error,color: Colors.green,),
Icon(Icons.fingerprint,color: Colors.green,),
],
)
Icons
類中包含了所有 Material Design 圖標(biāo)的IconData
靜態(tài)變量定義。
我們也可以使用自定義字體圖標(biāo)。iconfont.cn 上有很多字體圖標(biāo)素材,我們可以選擇自己需要的圖標(biāo)打包下載后,會(huì)生成一些不同格式的字體文件,在 Flutter 中,我們使用 ttf 格式即可。
假設(shè)我們項(xiàng)目中需要使用一個(gè)書籍圖標(biāo)和微信圖標(biāo),我們打包下載后導(dǎo)入:
fonts:
- family: myIcon #指定一個(gè)字體名
fonts:
- asset: fonts/iconfont.ttf
MyIcons
類,功能和Icons
類一樣:將字體文件中的所有圖標(biāo)都定義成靜態(tài)變量: class MyIcons{
// book 圖標(biāo)
static const IconData book = const IconData(
0xe614,
fontFamily: 'myIcon',
matchTextDirection: true
);
// 微信圖標(biāo)
static const IconData wechat = const IconData(
0xec7d,
fontFamily: 'myIcon',
matchTextDirection: true
);
}
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MyIcons.book,color: Colors.purple,),
Icon(MyIcons.wechat,color: Colors.green,),
],
)
運(yùn)行后效果如圖3-22所示:
更多建議: