Flutter元件學習(二)—— Image
上一節中,我們講了 Flutter
中 Text
元件的一些用法以及 API
,本節我們繼續學習 Flutter
中的 Image
元件,同樣先上圖:

Image元件的構造方法
在 Android
中,我們都知道,圖片的顯示方式有很多,資源圖片、網路圖片、檔案圖片等等,在 Flutter
中也有多種方式,用來載入不同形式的圖片:
- **Image:**通過ImageProvider來載入圖片
- **Image.asset:**用來載入本地資源圖片
- **Image.file:**用來載入本地(File檔案)圖片
- **Image.network:**用來載入網路圖片
- **Image.memory:**用來載入Uint8List資源(byte陣列)圖片
1、Image
Image
的一個引數是 ImageProvider
,基本上所有形式的圖片載入都是依賴它,這個類裡面就是實現圖片載入的原理。用法如下:
new Image(image: new AssetImage('images/logo.png')); new Image(image: new NetworkImage('http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg')) 複製程式碼
2、Image.asset
載入一個本地資源圖片,和 Android
一樣,有多種解析度的圖片可供選擇,但是沿襲的是 iOS
的圖片風格,分為 1x
, 2x
, 3x
,具體做法是在專案的根目錄下建立兩個資料夾,如下圖所示:

然後需要在 pubspec.yaml
檔案中宣告一下:
flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true assets: - images/logo.png - images/2.0x/logo.png - images/3.0x/logo.png 複製程式碼
用法如下:
new Image.asset('images/logo.png') 複製程式碼
3、Image.file
載入一個本地 File
圖片,比如相簿中的圖片,用法如下
new Image.file(new File('/storage/xxx/xxx/test.jpg')) 複製程式碼
4、Image.network
載入一個網路圖片,用法如下:
new Image.network('http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg') 複製程式碼
有的時候我們需要像Android那樣使用一個佔位圖或者圖片加載出錯時顯示某張特定的圖片,這時候需要用到 FadeInImage
這個元件:
new FadeInImage.assetNetwork( placeholder: 'images/logo.png', image: imageUrl, width: 120, fit: BoxFit.fitWidth, ) new FadeInImage.memoryNetwork( placeholder: kTransparentImage, image: imageUrl, width: 120, fit: BoxFit.fitWidth, ) 複製程式碼
第一種方法是載入一個本地的佔位圖,第二種是載入一個透明的佔位圖,但是需要注意的是,這個元件是不可以設定加載出錯顯示的圖片的;這裡有另一種方法可以使用第三方 package
的 CachedNetworkImage
元件:
new CachedNetworkImage( width: 120, fit: BoxFit.fitWidth, placeholder: new CircularProgressIndicator(), imageUrl: imageUrl, errorWidget: new Icon(Icons.error), ) 複製程式碼
CachedNetworkImage
元件中的佔位圖是一個 Widget
,這樣的話就可以自定義了,你想使用什麼樣的元件進行佔位都行,同樣加載出錯的佔位圖也是一個元件,也可以自己定義;該元件也是通過快取來載入圖片的。
5、Image.memory
用來將一個 byte
陣列載入成圖片,用法如下:
new Image.memory(bytes) 複製程式碼
Text元件的API
API名稱 | 功能 |
---|---|
width & height | 用來指定顯示圖片區域的寬高(並非圖片的寬高) |
fit | 設定圖片填充,類似於Android中的ScaleType |
color & colorBlendMode | 這兩個屬性需要配合使用,就是顏色和圖片混合,就類似於Android中的Xfermode |
alignment | 用來控制圖片擺放的位置 |
repeat | 用來設定圖片重複顯示(repeat-x水平重複,repeat-y垂直重複,repeat兩個方向都重複,no-repeat預設情況不重複) |
centerSlice | 設定圖片內部拉伸,相當於在圖片內部設定了一個.9圖,但是需要注意的是,要在顯示圖片的大小大於原圖的情況下才可以使用這個屬性,要不然會報錯 |
matchTextDirection | 這個需要配合Directionality進行使用 |
gaplessPlayback | 當圖片發生改變之後,重新載入圖片過程中的樣式(1、原圖片保留) |
fit
屬性中有很多值可以設定:
屬性名稱 | 樣式 |
---|---|
BoxFit.contain | 全圖居中顯示但不充滿,顯示原比例 |
BoxFit.cover | 圖片可能拉伸,也可能裁剪,但是充滿容器 |
BoxFit.fill | 全圖顯示且填充滿,圖片可能會拉伸 |
BoxFit.fitHeight | 圖片可能拉伸,可能裁剪,高度充滿 |
BoxFit.fitWidth | 圖片可能拉伸,可能裁剪,寬度充滿 |
BoxFit.scaleDown | 效果和contain差不多, 但是隻能縮小圖片,不能放大圖片 |
colorBlendMode
屬性中有很多值可以設定,由於可選值太多,這裡就不一一介紹了,有興趣的可以去 ofollow,noindex">官網colorBlendMode屬性介紹 看看
實現圓角/圓形圖片
1、圓角
很多時候我們需要給圖片設定圓角,那麼在flutter中是怎麼實現的呢?有很多種方法可以實現,下面我舉兩個例子:
使用裁剪來實現圖片圓角: new ClipRRect( child: Image.network( imageUrl, scale: 8.5, fit: BoxFit.cover, ), borderRadius: BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20), ), ) 使用邊框來實現圖片圓角: new Container( width: 120, height: 60, decoration: BoxDecoration( shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(10.0), image: DecorationImage( image: NetworkImage(imageUrl), fit: BoxFit.cover), ), ) 複製程式碼
需要注意的是,使用邊框實現的時候要注意設定 fit
屬性,不然效果也是有問題的,當然了你還可以使用 Material
元件來實現,這個大家可以自己去嘗試。
2、圓形
圓形圖片用得最多的應該是頭像之類的,這種同樣有多種方式可以實現,下面我也舉兩個例子:
使用裁剪實現圓形圖片: new ClipOval( child: Image.network( imageUrl, scale: 8.5, ), ) 使用CircleAvatar來實現圓形圖片: new CircleAvatar( backgroundImage: NetworkImage(imageUrl), radius: 50.0, ) 複製程式碼
當然了,你還可以使用邊框 BoxDecoration
來實現,效果也是一樣的。
下面來看一下詳細的程式碼實現:
class _ImageViewWidget extends State<ImageViewWidget> { var imageUrl = "http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg"; var imageUrl2 = "http://n.sinaimg.cn/sports/2_img/upload/4f160954/107/w1024h683/20181128/Yrxn-hpinrya6814381.jpg"; @override Widget build(BuildContext context) { return new Align( child: ListView( children: <Widget>[ new Text('資源圖片:'), new Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Padding( padding: const EdgeInsets.all(10.0), child: Image.asset( 'images/logo.png', ), ), //new Image.file( //File('/storage/emulated/0/Download/test.jpg'), //width: 120, ////fill(全圖顯示且填充滿,圖片可能會拉伸),contain(全圖顯示但不充滿,顯示原比例),cover(顯示可能拉伸,也可能裁剪,充滿) ////fitWidth(顯示可能拉伸,可能裁剪,寬度充滿),fitHeight顯示可能拉伸,可能裁剪,高度充滿),scaleDown(效果和contain差不多,但是) //), ], ), new Text('網路佔位圖片CachedNetworkImage:'), new Padding( padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Image.network( imageUrl, scale: 8.5, ), new Padding( padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0), child: CachedNetworkImage( width: 120, fit: BoxFit.fitWidth, placeholder: Image(image: AssetImage('images/logo.png')), imageUrl: imageUrl, errorWidget: new Icon(Icons.error), ), ), new CachedNetworkImage( imageUrl: imageUrl, width: 120, fit: BoxFit.fitWidth, placeholder: CircularProgressIndicator(), errorWidget: new Icon(Icons.error), ) ], ), ), new Text('網路佔位圖片FadeInImage:'), new Padding( padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), child: new Row( children: <Widget>[ new FadeInImage.memoryNetwork( placeholder: kTransparentImage, image: imageUrl, width: 120, fit: BoxFit.fitWidth, ), new Padding( padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0), child: new FadeInImage.assetNetwork( placeholder: 'images/logo.png', image: imageUrl, width: 120, fit: BoxFit.fitWidth, ), ), ], mainAxisAlignment: MainAxisAlignment.center, ), ), new Text('圓形圓角圖片:'), new Padding( padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new ClipOval( child: Image.network( imageUrl, width: 100, height: 100, fit: BoxFit.fitHeight, ), ), new Padding( padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0), child: ClipOval( child: Image.asset( 'images/logo.png', width: 100, height: 100, fit: BoxFit.fitHeight, ), ), ), new ClipRRect( child: Image.network( imageUrl, scale: 8.5, fit: BoxFit.cover, ), borderRadius: BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20), ), ) ], ), ), new Text('顏色混合圖片:'), new Padding( padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Image.asset( 'images/logo.png', color: Colors.red, colorBlendMode: BlendMode.darken, ), new Padding( padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0), child: Image.network( imageUrl, scale: 8.5, colorBlendMode: BlendMode.colorDodge, color: Colors.blue, ), ), ], ), ), new Text('centerSlice圖片內部拉伸:'), new Padding( padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), child: new Image.asset( 'images/logo.png', width: 250, height: 250, fit: BoxFit.contain, centerSlice: new Rect.fromCircle(center: const Offset(20, 20), radius: 1), ), ), new Text('matchTextDirection圖片內部方向'), new Padding( padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Directionality( textDirection: TextDirection.ltr, child: Image.network( imageUrl, height: 100, matchTextDirection: true, fit: BoxFit.fitHeight, ), ), new Padding( padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0), child: Directionality( textDirection: TextDirection.rtl, child: Image.network( imageUrl, height: 100, matchTextDirection: true, fit: BoxFit.fitHeight, ), ), ), ], ), ), new Text('點選替換圖片'), new Padding( padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), child: Row( children: <Widget>[ new RaisedButton( onPressed: () { setState(() { widget.networkImage = new NetworkImage(imageUrl2, scale: 8.5); }); }, child: Text('點選更換圖片'), ), new Image( gaplessPlayback: false, fit: BoxFit.contain, image: widget.networkImage, ), ], ), ) ], ), ); } } 複製程式碼
程式碼已上傳至 Github
公眾號
歡迎關注我的個人公眾號【IT先森養成記】,專注大前端技術分享,包含Android,Java,Kotlin,Flutter,HTML,CSS,JS等技術;在這裡你能得到的不止是技術上的提升,還有一些學習經驗以及志同道合的朋友,趕快加入我們,一起學習,一起進化吧!!!
