老孟導讀:大家好,這是【Flutter實戰】系列文章的第三篇,這一篇講解圖片組件,Image有很多高級用法,希望對您有所幫助。 圖片組件是Flutter基礎組件之一,和文本組件一樣必不可少。圖片組件包含Image和Icon兩個組件,本質上Icon不屬於圖片組件,但其外形效果上類似於圖片。 在項目中建 ...
老孟導讀:大家好,這是【Flutter實戰】系列文章的第三篇,這一篇講解圖片組件,Image有很多高級用法,希望對您有所幫助。
圖片組件是Flutter基礎組件之一,和文本組件一樣必不可少。圖片組件包含Image和Icon兩個組件,本質上Icon不屬於圖片組件,但其外形效果上類似於圖片。
在項目中建議優先使用Icon組件,Icon本質上是一種字體,只不過顯示的不是文字,而是圖標,而Image組件先通過圖片解碼器將圖片解碼,所以Icon有如下優點:
- 通常情況下,圖標比圖片體積更小,顯著的減少App包體積。
- 圖標不會出現失真或者模糊的現象,例如將20x20的圖片,渲染在200x200的屏幕上,圖片會失真或模糊,而圖標是矢量圖,不會失真,就像字體一樣。
- 多個圖標可以存放在一個文件中,方便管理。
- 全平臺通用。
Image
Image組件用於顯示圖片,圖片的來源可以是網路、項目中圖片或者設備上的圖片。
載入網路圖片:
Image.network(
'http://pic1.win4000.com/pic/c/cf/cdc983699c.jpg',
)
載入項目中圖片:
首先將圖片拷貝到項目中,通常情況下,拷貝到assets/images/
目錄下,assets/images/
目錄為手動創建,新建的項目預設是沒有此目錄的。
設置pubspec.yaml
配置文件:
assets:
- assets/images/
或者指定具體圖片的名稱:
assets:
- assets/images/aa.jpg
通常情況下,使用第一種方式,因為圖片會有很多張,增加一張就這裡配置一個太麻煩。
註意:assets前面的空格問題,極容易引發編譯異常,正確格式如下:
載入圖片:
Image.asset('assets/images/aa.jpg')
載入設備上的圖片:
要載入設備(手機)上的圖片首先需要獲取設備圖片的路徑,由於不同平臺的路徑不同,因此路徑的獲取必須依靠原生支持,如果瞭解原生(Android和iOS)開發,可以直接使用MethodChannel獲取路徑,如果不懂原生(Android和iOS)開發,可以使用第三方插件獲取路徑,這裡推薦官方的path_provider。
載入設備上的圖片:
Image.file(File('path'))
設置圖片的大小:
Image.asset('assets/images/aa.jpg',width: 100,height: 200,),
當Image的大小和圖片大小不匹配時,需要設置填充模式fit
,設置組件大小為150x150,
Container(
color: Colors.red.withOpacity(.3),
child: Image.asset('assets/images/aa.jpg',width: 150,height: 150),
)
看到,圖片左右兩邊有空白區域(淺紅色填充的區域),如果想要圖片充滿整個區域,設置如下:
Container(
color: Colors.red.withOpacity(.3),
child: Image.asset('assets/images/aa.jpg',width: 150,height: 150,fit: BoxFit.fill,),
)
雖然圖片充滿整個區域,但圖片變形了,使圖片等比拉伸,直到兩邊都充滿區域:
Container(
color: Colors.red.withOpacity(.3),
child: Image.asset('assets/images/aa.jpg',width: 150,height: 150,fit: BoxFit.cover,),
)
此時,圖片未變形且兩邊都充滿區域,不過圖片被裁減了一部分。
fit
參數就是設置填充方式,其值介紹如下:
- fill:完全填充,寬高比可能會變。
- contain:等比拉伸,直到一邊填充滿。
- cover:等比拉伸,直到2邊都填充滿,此時一邊可能超出範圍。
- fitWidth:等比拉伸,寬填充滿。
- fitHeight:等比拉伸,高填充滿。
- none:當組件比圖片小時,不拉伸,超出範圍截取。
- scaleDown:當組件比圖片小時,圖片等比縮小,效果和contain一樣。
BoxFit.none
的裁減和alignment
相關,預設居中,
Image.asset(
'assets/images/aa.jpg',
width: 150,
height: 150,
fit: BoxFit.none,
alignment: Alignment.centerRight,
),
左邊為原圖。
設置對齊方式:
Container(
color: Colors.red.withOpacity(.3),
child: Image.asset(
'assets/images/aa.jpg',
width: 150,
height: 150,
alignment: Alignment.centerLeft,
),
),
color
和colorBlendMode
用於將顏色和圖片進行顏色混合,colorBlendMode
表示混合模式,下麵介紹的混合模式比較多,瀏覽一遍即可,此屬性可以用於簡單的濾鏡效果。
- clear:清楚源圖像和目標圖像。
- color:獲取源圖像的色相和飽和度以及目標圖像的光度。
- colorBurn:將目標的倒數除以源,然後將結果倒數。
- colorDodge:將目標除以源的倒數。
- darken:通過從每個顏色通道中選擇最小值來合成源圖像和目標圖像。
- difference:從每個通道的較大值中減去較小的值。合成黑色沒有效果。合成白色會使另一張圖像的顏色反轉。
- dst:僅繪製目標圖像。
- dstATop:將目標圖像合成到源圖像上,但僅在與源圖像重疊的位置合成。
- dstIn:顯示目標圖像,但僅顯示兩個圖像重疊的位置。不渲染源圖像,僅將其視為蒙版。源的顏色通道將被忽略,只有不透明度才起作用。
- dstOut:顯示目標圖像,但僅顯示兩個圖像不重疊的位置。不渲染源圖像,僅將其視為蒙版。源的顏色通道將被忽略,只有不透明度才起作用。
- dstOver:將源圖像合成到目標圖像下。
- exclusion:從兩個圖像的總和中減去兩個圖像的乘積的兩倍。
- hardLight:調整源圖像和目標圖像的成分以使其適合源圖像之後,將它們相乘。
- hue:獲取源圖像的色相,以及目標圖像的飽和度和光度。
- lighten:通過從每個顏色通道中選擇最大值來合成源圖像和目標圖像。
- luminosity:獲取源圖像的亮度,以及目標圖像的色相和飽和度。
- modulate:將源圖像和目標圖像的顏色分量相乘。
- multiply:將源圖像和目標圖像的分量相乘,包括alpha通道。
- overlay:調整源圖像和目標圖像的分量以使其適合目標後,將它們相乘。
- plus:對源圖像和目標圖像的組成部分求和。
- saturation:獲取源圖像的飽和度以及目標圖像的色相和亮度。
- screen:將源圖像和目標圖像的分量的逆值相乘,然後對結果求逆。
- softLight:對於低於0.5的源值使用colorDodge,對於高於0.5的源值使用colorBurn。
- src:放置目標圖像,僅繪製源圖像。
- srcATop:將源圖像合成到目標圖像上,但僅在與目標圖像重疊的位置合成。
- srcIn:顯示源圖像,但僅顯示兩個圖像重疊的位置。目標圖像未渲染,僅被視為蒙版。目標的顏色通道將被忽略,只有不透明度才起作用。
- srcOut:顯示源圖像,但僅顯示兩個圖像不重疊的位置。
- srcOver:將源圖像合成到目標圖像上。
- xor:將按位異或運算符應用於源圖像和目標圖像。
是不是感覺看了和沒看差不多,看了也看不懂。正常,估計只有學過視覺演算法的才能看懂吧,直接看下各個屬性的效果吧:
repeat
表示當組件有空餘位置時,將會重覆顯示圖片
Image.asset(
'assets/images/aa.jpg',
width: double.infinity,
height: 150,
repeat: ImageRepeat.repeatX,
)
重覆的模式有:
- repeat:x,y方向都充滿。
- repeatX:x方向充滿。
- repeatY:y方向充滿。
- noRepeat:不重覆。
matchTextDirection
設置為true時,圖片的繪製方向為TextDirection設置的方向,其父組件必須為Directionality:
Directionality(
textDirection: TextDirection.rtl,
child: Image.asset(
'assets/images/logo.png',
height: 150,
matchTextDirection: true,
)),
左邊為原圖,效果是左右鏡像。
filterQuality
表示繪製圖像的質量,從高到低為:high->medium->low->none。越高效果越好,越平滑,當然性能損耗越大,預設是low
,如果發現圖片有鋸齒,可以設置此參數。
當載入圖片的時候回調frameBuilder
,當此參數為null時,此控制項將會在圖片載入完成後顯示,未載入完成時顯示空白,尤其在載入網路圖片時會更明顯。因此此參數可以用於處理圖片載入時顯示占點陣圖片和載入圖片的過渡效果,比如淡入淡出效果。
下麵的案例是淡入淡出效果:
Image.network(
'https://flutter.github.io/assets-for-api-docs/assets/widgets/puffin.jpg',
frameBuilder: (BuildContext context, Widget child, int frame,
bool wasSynchronouslyLoaded) {
if (wasSynchronouslyLoaded) {
return child;
}
return AnimatedOpacity(
child: child,
opacity: frame == null ? 0 : 1,
duration: const Duration(seconds: 2),
curve: Curves.easeOut,
);
},
)
loadingBuilder
參數比frameBuilder
控制的力度更細,可以獲取圖片載入的進度,下麵的案例顯示了載入進度條:
Image.network(
'https://flutter.github.io/assets-for-api-docs/assets/widgets/puffin.jpg',
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) {
return child;
}
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
})
centerSlice
用於.9圖,.9圖用於拉伸圖片的特定區域,centerSlice
設置的區域(Rect)就是拉伸的區域。.9圖通常用於控制項大小、寬高比不固定的場景,比如聊天背景圖片等。
Container(
width: 250,
height: 300,
decoration: BoxDecoration(
image: DecorationImage(
centerSlice: Rect.fromLTWH(20, 20, 10, 10),
image: AssetImage(
'assets/images/abc.jpg',
),
fit: BoxFit.fill))),
上面為原圖,下麵為拉伸的圖片。
在使用時大概率會出現如下異常:
這是由於圖片比組件的尺寸大,如果使用centerSlice
屬性,圖片必須比組件的尺寸小,一般情況下,.9圖的尺寸都非常小。
Icon
Icon是圖標組件,Icon不具有交互屬性,如果想要交互,可以使用IconButton。
Icon(Icons.add),
設置圖標的大小和顏色:
Icon(
Icons.add,
size: 40,
color: Colors.red,
)
上面的黑色為預設大小和顏色。
Icons.add
是系統提供的圖標,創建Flutter項目的時候,pubspec.yaml
中預設有如下配置:
所有的圖標在Icons中已經定義,可以直接在源代碼中查看,也可以到官網查看所有圖標。
所有圖標效果如下:
案例
聊天背景(.9圖實現)
Container(
width: 200,
padding: EdgeInsets.only(left: 8,top: 8,right: 20,bottom: 8),
decoration: BoxDecoration(
image: DecorationImage(
centerSlice: Rect.fromLTWH(20, 20, 1, 1),
image: AssetImage(
'assets/images/chat.png',
),
fit: BoxFit.fill)),
child: Text('老孟,專註分享Flutter技術和應用實戰。'
'老孟,專註分享Flutter技術和應用實戰。'
'老孟,專註分享Flutter技術和應用實戰。',),
)
背景圖片大小是57x80:
右側三角已經不在中間了,如果想讓其一直保持居中,修改拉伸區域:
centerSlice: Rect.fromLTWH(20, 10, 1, 60),
圓形帶邊框的頭像
Container(
width: 100,
height: 100,
padding: EdgeInsets.all(3),
decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.blue),
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: AssetImage('assets/images/aa.jpg'), fit: BoxFit.cover)),
),
)
圖片占位符:
Image.network(
'https://flutter.github.io/assets-for-api-docs/assets/widgets/puffin.jpg',
height: 150,
width: 150,
fit: BoxFit.cover,
frameBuilder: (
BuildContext context,
Widget child,
int frame,
bool wasSynchronouslyLoaded,
) {
if (frame == null) {
return Image.asset(
'assets/images/place.png',
height: 150,
width: 150,
fit: BoxFit.cover,
);
}
return child;
},
)
添加自己的圖標庫
如果系統提供的圖標沒有我們想要的圖標,這時需要引入第三方庫的圖標,下麵以阿裡巴巴的圖標庫為例。
打開阿裡巴巴的圖標官網,找到自己想要的圖標後,將滑鼠放置到圖標上,加入購物車:
點擊右上角的購物車,然後點擊添加至項目:
如果沒有添加過項目,需要創建一個新項目:
創建好後加入此項目,跳轉到我的項目
頁面,點擊下載:
解壓下載的文件,解壓出來的文件有好幾個,如下圖:
選擇iconfont.ttf
文件拷貝到 Flutter 項目的assets/fonts
目錄下,assets/fonts
目錄預設是沒有的,需要手動創建,在pubspec.yaml
設置如下:
千萬註意紅框內開頭的空格問題,否則編譯不通過,family
後面跟的字元串最好有意義,後面用圖標的時候需要用到。
用法如下:
Icon(IconData(0xe613,fontFamily: 'appIconFonts')
0xe613
在下載圖標時已經標註,將&#
替換為0
,如下圖:
fontFamily
是在pubspec.yaml
中設置的family
屬性,第三方的圖標和系統圖標一樣,可以設置其顏色和大小。
交流
老孟Flutter博客地址(330個控制項用法):http://laomengit.com
歡迎加入Flutter交流群(微信:laomengit)、關註公眾號【老孟Flutter】: