Flutter中,可以通過Image組件來加載并顯示圖片,Image的數(shù)據(jù)源可以是asset、文件、內(nèi)存以及網(wǎng)絡(luò)。
- ImageProvider
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??梢宰孕胁殚單臋nImageProvider
1.從asset中加載圖片
在工程根目錄下創(chuàng)建一個(gè)文件夾,并將圖片拷貝到文件夾。在pubspec.yaml中的flutter部分添加如下內(nèi)容:
assets:
- assets/images/avatar.png
然后執(zhí)行flutter pub get。
ps:yaml文件對(duì)縮進(jìn)嚴(yán)格,所以必須嚴(yán)格按照每一層兩個(gè)空格的方式進(jìn)行縮進(jìn),此處assets前面應(yīng)有兩個(gè)空格。筆者習(xí)慣創(chuàng)建兩層文件夾assets放圖片資源、字體資源等,images專門放圖片資源,所以在pubspec.yaml中配置assets/images/avatar.png
加載圖片代碼示例如下:
class AssetImageDefault1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Image(
image: AssetImage('assets/images/avatar.png'),
width: 200,
height: 200,
alignment: Alignment.center,
);
}
}
Image也提供了一個(gè)快捷的構(gòu)造函數(shù)Image.asset用于顯示圖片,代碼示例如下:
class ImageAssetDefault2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Image.asset(
'assets/images/avatar.png',
width: 200,
height: 200,
alignment: Alignment.center,
);
}
}
運(yùn)行上面兩個(gè)示例,效果圖如下:
如果加載時(shí)報(bào)錯(cuò)找不到圖片資源,有可能是兩個(gè)原因:
1.pubspec.yaml中書寫不規(guī)范。不規(guī)范的縮進(jìn)和字符都可能導(dǎo)致配置的內(nèi)容不生效。要注意yaml的一個(gè)縮進(jìn)是2個(gè)空格。如下圖所示:

2.代碼中的圖片相對(duì)路徑要和工程中實(shí)際路徑不一致。例如:項(xiàng)目flutter_demo/assets/images/demo.png,引用路徑:
AssetImage('assets/images/demo.png')
2.從網(wǎng)絡(luò)加載圖片
代碼示例如下:
class ImageNetWorkDefault1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Image(
image: NetworkImage(
'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg'),
width: 200,
height: 200,
alignment: Alignment.center,
);
}
}
Image也提供了一個(gè)快捷的構(gòu)造函數(shù)Image.network用于加載網(wǎng)絡(luò)圖片,代碼示例如下:
class ImageNetWorkDefault2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Image.network(
'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl-2.jpg',
width: 200,
height: 200,
);
}
}
代碼運(yùn)行效果圖如下:
3.參數(shù)
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ì)拉伸填充滿顯示空間,圖片本身長寬比會(huì)發(fā)生變化,圖片會(huì)變形。
cover:會(huì)按圖片的長寬比放大后居中填滿顯示空間,圖片不會(huì)變形,超出顯示空間部分會(huì)被剪裁。
contain:圖片的默認(rèn)適應(yīng)規(guī)則,圖片會(huì)在保證圖片本身長寬比不變的情況下縮放以適應(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值,代碼示例如下:
class FitImageDemo extends StatelessWidget {
final imageName = 'assets/images/avatar.png';
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Image>[
Image.asset(
imageName,
height: 50,
width: 50,
fit: BoxFit.fill,
),
Image.asset(
imageName,
height: 50,
width: 50,
fit: BoxFit.contain,
),
Image.asset(
imageName,
width: 100,
height: 50,
fit: BoxFit.cover,
),
Image.asset(
imageName,
width: 100,
height: 50,
fit: BoxFit.fitWidth,
),
Image.asset(
imageName,
width: 100,
height: 50,
fit: BoxFit.fitHeight,
),
Image.asset(
imageName,
width: 100,
height: 50,
fit: BoxFit.scaleDown,
),
Image.asset(
imageName,
width: 100,
height: 50,
fit: BoxFit.none,
),
].map((e) {
return Row(
children: <Widget>[
Padding(
padding: EdgeInsets.all(16.0),
child: SizedBox(
width: 100,
child: e,
),
),
Text(e.fit.toString()),
],
);
}).toList(),
),
);
}
}
代碼運(yùn)行效果圖如下:
- color colorBlendMode
在圖片繪制時(shí)可以對(duì)每一個(gè)像素進(jìn)行顏色混合處理,color指定混合色,colorBlendMode指定混合模式,代碼示例:
Image.asset(
'assets/images/avatar.png',
width: 100,
color: Colors.blue,
colorBlendMode: BlendMode.difference,
),
運(yùn)行效果如下:
- repeat
當(dāng)圖片本身大小小于顯示空間時(shí),指定圖片的重復(fù)規(guī)則。代碼示例如下:
Image.asset(
'assets/images/avatar.png',
width: 100,
height: 200,
repeat: ImageRepeat.repeatY,
),
代碼運(yùn)行效果圖如下:
4.實(shí)現(xiàn)圓角圖像
實(shí)現(xiàn)圓角圖像有多種方式。
- CircleAvatar
CircleAvatar可以實(shí)現(xiàn)圓角頭像,也可以添加一個(gè)子Widget。源碼如下:
const CircleAvatar({
Key key,
this.child, // 子Widget
this.backgroundColor, // 背景顏色
this.backgroundImage, // 背景圖像
this.foregroundColor, // 前景顏色
this.radius, // 半徑
this.minRadius, // 最小半徑
this.maxRadius, // 最大半徑
})
代碼示例如下:
class CircleAvatarImage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CircleAvatar(
radius: 100,
backgroundImage: NetworkImage(
'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg'),
child: Container(
alignment: Alignment.center,
width: 100,
height: 100,
child: Text('貓頭鷹'),
),
);
}
}
運(yùn)行效果圖如下:
- ClipOval
ClipOval也可以實(shí)現(xiàn)圓角頭像,通常是在只有頭像時(shí)使用。代碼示例如下:
class ClipOvalImage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ClipOval(
child: Image.network(
'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl-2.jpg',
width: 100,
height: 100,
),
);
}
}
運(yùn)行效果圖如下:
- ClipRRect
ClipRRect用于實(shí)現(xiàn)圓角效果,可以設(shè)置圓角的大小。代碼示例如下:
class ClipRRectImage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.network(
'https://tva1.sinaimg.cn/large/006y8mN6gy1g7aa03bmfpj3069069mx8.jpg',
width: 100,
height: 100,
),
);
}
}
運(yùn)行效果圖如下:
5.加載網(wǎng)絡(luò)圖片時(shí)顯示占位圖
加載網(wǎng)絡(luò)圖片時(shí)顯示占位圖可以用FadeInImage,部分源碼如下:
const FadeInImage({
@required this.placeholder,
@required this.image,
this.fadeOutDuration = const Duration(milliseconds: 300),
this.fadeInDuration = const Duration(milliseconds: 700),
this.width,
this.height,
...
})
/// Image displayed while the target [image] is loading.
final ImageProvider placeholder;
/// The target image that is displayed once it has loaded.
final ImageProvider image;
- placeholder
默認(rèn)顯示的占位圖 - image
真正顯示的圖片 - fadeOutDuration fadeOutDuration
placeholder消失image顯示的過程有一個(gè)淡進(jìn)淡出,fadeOutDuration和fadeOutDuration就是設(shè)置淡進(jìn)淡出的時(shí)間,不想那個(gè)要這種效果將Duration設(shè)置1毫秒,不可以設(shè)置為0。
代碼示例如下:
class FadeImageDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: FadeInImage(
placeholder: AssetImage('assets/images/avatar.png'),
image: NetworkImage(
'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl-2.jpg'),
fadeInDuration: Duration(milliseconds: 1),
fadeOutDuration: Duration(milliseconds: 1),
width: 200,
height: 200,
),
);
}
}
但是這種方法沒有緩存每次都需要一段時(shí)間加載網(wǎng)絡(luò)圖片,cached_network_image 這個(gè)庫實(shí)現(xiàn)了圖片緩存加載和占位圖效果,可自行查閱文檔。