Image 圖片作爲日常中最常用的 Widget 卻也是最容易忽略的,小菜在日常中通常僅用到 Image 展示圖片屬性,但是 Image 本身非常強大,有很多小菜所不熟知的屬性特徵;今天小菜重新認識一下 Image Widget;
Image
Image 作爲支持展示多種圖片格式的 Widget,提供了多種構造方法;
- Image() 用於從 ImageProvider 中獲取圖片資源;
- Image.asset() 用於從 AssetBundle 中獲取工程目錄圖片資源;
- Image.network() 用於從 URL 中獲取網絡圖片資源;
- Image.file() 用於從 File 中獲取本地圖片資源;
-
Image.memory() 用於從 Uint8List 中獲取內存圖片資源;
源碼分析
const Image({
Key key,
@required this.image, // 圖片資源
this.frameBuilder, // 幀構造器
this.loadingBuilder, // 加載過程幀構造器
this.errorBuilder, // 失敗狀態幀構造器
this.semanticLabel,
this.excludeFromSemantics = false,
this.width, // 圖片寬
this.height, // 圖片高
this.color, // 圖片顏色
this.colorBlendMode, // 混合方式
this.fit, // 分佈效果
this.alignment = Alignment.center, // 對齊方式
this.repeat = ImageRepeat.noRepeat, // 平鋪效果
this.centerSlice,
this.matchTextDirection = false,
this.gaplessPlayback = false,
this.isAntiAlias = false,
this.filterQuality = FilterQuality.low,
})
簡單分析源碼可得,Image 作爲一個有狀態的 StatefulWidget,主要通過 image 屬性來設置圖片資源,多種附加屬性來支持圖片更多樣的展示效果;小菜逐一進行嘗試學習;
案例嘗試
1. image
Image 通過 ImageProvider 來展示圖片,Flutter 提供了多種方式,與各類命名構造方法對應;
_imageWid00(isNet) => Image(
image: isNet
? NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg')
: AssetImage('images/icon_hzw01.jpg'));
2. frameBuilder
typedef ImageFrameBuilder = Widget Function(
BuildContext context,
Widget child,
int frame,
bool wasSynchronouslyLoaded,
);
frameBuilder 幀構造器用於控制在 Image 構建時小部件簽名,其中 child 用於保存默認 Image 圖片並且不可爲空;frame 爲渲染 Image 幀數下標,默認爲首幀;可以通過 frameBuilder 設置圖片基本樣式;
_imageWid01(isNet) {
return Image(
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
},
image: isNet
? NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg')
: AssetImage('images/icon_hzw01.jpg'));
}
3. loadingBuilder
loadingBuilder 加載狀態幀構造器,在加載過程中展示的 Image 構造器;查看效果圖可以看到,設置了兩層內邊距,因爲在 loading 狀態和加載完狀態時都對 child 設置了內邊距;
_imageWid02(isNet) {
return Image(
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
},
loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent loadingProgress) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.green.withOpacity(0.4),
child: child);
},
image: isNet
? NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg')
: AssetImage('images/icon_hzw01.jpg'));
}
4. errorBuilder
errorBuilder 爲失敗時替換 Image 展示的構造器;
_imageWid03(isNet) {
return Image(
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
},
loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent loadingProgress) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.green.withOpacity(0.4),
child: child);
},
errorBuilder: (BuildContext context, Object exception, StackTrace stackTrace) {
return Container(
height: 100.0, padding: EdgeInsets.all(18.0),
color: Colors.grey.withOpacity(0.4),
child: Center(child: Icon(Icons.error)));
},
image: isNet
? NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl11.jpg')
: AssetImage('images/icon_hzw0111.jpg'));
}
5. width & height
width & height 爲設置圖片展示寬高尺寸;
_imageWid05(width, height) => Image(image: AssetImage('images/icon_hzw01.jpg'), width: width, height: height);
6. color & colorBlendMode
color & colorBlendMode 配合使用繪製的混合模式,可以用來創建其他效果,如黑白模式,X 光特效等;之前小菜有所嘗試;
_imageWid06(isNet, index) {
BlendMode blendMode;
if (index == 0) {
blendMode = BlendMode.difference;
} else if (index == 1) {
blendMode = BlendMode.screen;
} else if (index == 2) {
blendMode = BlendMode.hardLight;
} else {
blendMode = BlendMode.colorBurn;
}
return Image(
color: Colors.indigoAccent.withOpacity(0.4),
colorBlendMode: blendMode,
image: isNet
? NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg')
: AssetImage('images/icon_hzw01.jpg'));
}
7. alignment
alignment 爲邊界內的對齊方式;當圖片資源小於圖片尺寸時,可以通過 Alignment 調整對齊方式;
_imageWid07(index) {
Alignment alignment;
if (index == 0) {
alignment = Alignment.topLeft;
} else if (index == 1) {
alignment = Alignment.center;
} else {
alignment = Alignment.bottomRight;
}
return Image(
image: AssetImage('images/icon_wechat_moments.png'),
alignment: alignment,
height: 120,
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(2.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
});
}
8. repeat
repeat 爲覆蓋圖片未覆蓋區域樣式,包括水平方向或豎直方向平鋪效果;
_imageWid08(index) {
ImageRepeat repeat;
if (index == 0) {
repeat = ImageRepeat.repeatX;
} else if (index == 1) {
repeat = ImageRepeat.repeatY;
} else {
repeat = ImageRepeat.repeat;
}
return Image(
image: AssetImage('images/icon_wechat_moments.png'),
repeat: repeat, height: 120,
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(18.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
});
}
9. fit
fit 爲圖片在佈局中的分佈效果;
- BoxFit.fitWidth:整體圖片資源以圖片寬度爲基準放大或縮小;
- BoxFit.fitHeight:整體圖片資源以圖片高度爲基準放大或縮小;
- BoxFit.fill:整體圖片填充滿圖片寬高,可進行拉伸或壓縮等;
- BoxFit.contain:整體圖片按比例放大或縮小至最大寬或高可容納範圍,並在設置寬高內居中整體顯示;
- BoxFit.cover:整體圖片按比例放大或縮小至最小寬或高可容納範圍,並居中顯示;
- BoxFit.scaleDown:整體圖片大於設置尺寸,按比例縮小並居中顯示;若整體圖片小於設置尺寸,則不做處理,居中顯示;
_imageWid09(index) {
BoxFit fit;
if (index == 0) {
fit = BoxFit.fitWidth;
} else if (index == 1) {
fit = BoxFit.fitHeight;
} else if (index == 2) {
fit = BoxFit.fill;
} else if (index == 3) {
fit = BoxFit.cover;
} else if (index == 4) {
fit = BoxFit.contain;
} else {
fit = BoxFit.scaleDown;
}
return Image(
image: AssetImage('images/icon_hzw03.jpg'),
fit: fit, height: 120,
frameBuilder: (BuildContext context, Widget child, int frame, bool wasSynchronouslyLoaded) {
return Container(
padding: EdgeInsets.all(2.0),
color: Colors.deepOrange.withOpacity(0.4),
child: child);
});
}
10. centerSlice
centerSlice 用於設置一個矩形,類似於 .9.png 圖一樣,進行固定範圍的拉伸;其中注意 fit 類型不可爲 BoxFit.none 或 BoxFit.cover;
_imageWid10(index) {
Rect rect;
if (index == 0) {
rect = null;
} else if (index == 1) {
rect = Rect.fromLTWH(100, 100, 50, 50);
} else if (index == 2) {
rect = Rect.fromLTWH(50, 50, 50, 50);
}
return Image(
fit: BoxFit.contain,
width: 250,
height: 250,
centerSlice: rect,
image: AssetImage('images/icon_music.png'));
}
小菜對 Image 的學習還僅限於基礎應用,對於平時不常用的屬性有了進一步瞭解,但對源碼的學習還不夠深入;如有錯誤,請多多指導!
來源: 阿策小和尚