Flutter實(shí)戰(zhàn) 圖片及ICON

2021-03-06 17:49 更新

#3.5.1 圖片

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。

#Image

Image widget 有一個(gè)必選的image參數(shù),它對(duì)應(yīng)一個(gè) ImageProvider。下面我們分別演示一下如何從 asset 和網(wǎng)絡(luò)加載圖片。

#從asset中加載圖片

  1. 在工程根目錄下創(chuàng)建一個(gè)images目錄,并將圖片 avatar.png 拷貝到該目錄。

  1. 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è)空格。

  1. 加載該圖片

   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,
   )

#從網(wǎng)絡(luò)加載圖片

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所示:

圖3-17

#參數(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ù)方式
  ...
})

  • widthheight:用于設(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所示:

圖3-18

  • colorcolorBlendMode:在圖片繪制時(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所示(彩色):

圖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所示:

圖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()
      ),
    );
  }
}

#Image緩存

Flutter 框架對(duì)加載過的圖片是有緩存的(內(nèi)存),默認(rèn)最大緩存數(shù)量是1000,最大緩存空間為 100M。關(guān)于 Image 的詳細(xì)內(nèi)容及原理我們將會(huì)在后面進(jìn)階部分深入介紹。

#3.5.2 ICON

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ì):

  1. 體積?。嚎梢詼p小安裝包大小。
  2. 矢量的:iconfont 都是矢量圖標(biāo),放大不會(huì)影響其清晰度。
  3. 可以應(yīng)用文本樣式:可以像文本一樣改變字體圖標(biāo)的顏色、大小對(duì)齊等。
  4. 可以通 過TextSpan 和文本混用。

#使用Material Design字體圖標(biāo)

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 封裝了IconDataIcon來專門顯示字體圖標(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)

我們也可以使用自定義字體圖標(biāo)。iconfont.cn 上有很多字體圖標(biāo)素材,我們可以選擇自己需要的圖標(biāo)打包下載后,會(huì)生成一些不同格式的字體文件,在 Flutter 中,我們使用 ttf 格式即可。

假設(shè)我們項(xiàng)目中需要使用一個(gè)書籍圖標(biāo)和微信圖標(biāo),我們打包下載后導(dǎo)入:

  1. 導(dǎo)入字體圖標(biāo)文件;這一步和導(dǎo)入字體文件相同,假設(shè)我們的字體圖標(biāo)文件保存在項(xiàng)目根目錄下,路徑為"fonts/iconfont.ttf":

   fonts:
     - family: myIcon  #指定一個(gè)字體名
       fonts:
         - asset: fonts/iconfont.ttf

  1. 為了使用方便,我們定義一個(gè)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
     );
   }

  1. 使用

   Row(
     mainAxisAlignment: MainAxisAlignment.center,
     children: <Widget>[
       Icon(MyIcons.book,color: Colors.purple,),
       Icon(MyIcons.wechat,color: Colors.green,),
     ],
   )

運(yùn)行后效果如圖3-22所示:

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)