【Flutter學習】基本組件之圖片組件Image


一,概述

  Image(圖片組件)是顯示圖像的組件,一個顯示圖片的widget,支持圖像格式:JPEG,PNG,GIF,動畫GIF,WebP,動畫WebP,BMP和WBMP。 Image組件有多種構造函數:

  • new Image: 從ImageProvider獲取圖像。
  • new Image.asset: 加載本地圖片文件。
  • new Image.file: 加載本地圖片文件。
  • new Image.network: 加載網絡圖片。
  • new Image.memory: 加載Uint8List資源圖片。

二,繼承關系

  • Object > Diagnosticablet > DiagnosticableTreet > Widgett > StatefulWidgett > Image

三,構造方法

  • new Image: 從ImageProvider獲取圖像。
    • 類名構造方法,它指定了圖片是從哪里加載,是從項目中還是網絡中等等。  
      const Image({
      Key key,
      @required this.image,
      this.frameBuilder,
      this.loadingBuilder,
      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.filterQuality = FilterQuality.low,
      }) : assert(image != null),
      assert(alignment != null),
      assert(repeat != null),
      assert(filterQuality != null),
      assert(matchTextDirection != null),
      super(key: key);
  • new Image.asset: 加載資源圖片文件。
    • 命名構造方法,用於使用key從AssetBundle獲取圖像。就是加載項目資源目錄中的圖片,加入圖片后會增大打包的包體體積,用的是相對路徑。
    • 其實就相當於第一種構造方法指定 ImageProvider 為 AssetImage
    • 沿襲的是 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')
    • 構造方法
    •   Image.asset(
          String name, {
          Key key,
          AssetBundle bundle,
          this.frameBuilder,
          this.semanticLabel,
          this.excludeFromSemantics = false,
          double scale,
          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,
          String package,
          this.filterQuality = FilterQuality.low,
        }) : image = scale != null
               ? ExactAssetImage(name, bundle: bundle, scale: scale, package: package)
               : AssetImage(name, bundle: bundle, package: package),
             loadingBuilder = null,
             assert(alignment != null),
             assert(repeat != null),
             assert(matchTextDirection != null),
             super(key: key);
  • new Image.file: 加載本地圖片文件。
    • 命名構造方法,加載本地圖片,就是加載本地文件中的圖片,這個是一個絕對路徑,跟包體無關。 用於從File獲取圖像
    • 其實就相當於第一種構造方法指定 ImageProvider 為 FlieImage
    • 加載一個本地 File 圖片,比如相冊中的圖片,用法如下
      new Image.file(new File('/storage/xxx/xxx/test.jpg'))
    • 構造函數
       Image.file(
          File file, {
          Key key,
          double scale = 1.0,
          this.frameBuilder,
          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.filterQuality = FilterQuality.low,
        }) : image = FileImage(file, scale: scale),
             loadingBuilder = null,
             assert(alignment != null),
             assert(repeat != null),
             assert(filterQuality != null),
             assert(matchTextDirection != null),
             super(key: key);
  • new Image.network: 加載網絡圖片。
    • 命名構造方法,用於從URL地址獲取圖像。意思就是你需要加入一段http://xxxx.xxx的這樣的網絡路徑地址。
      new Image.network('http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg')
    • 其實就相當於第一種構造方法指定 ImageProvider 為 NetworkImage。
    • 有的時候我們需要像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 組件:CachedNetworkImage 組件中的占位圖是一個 Widget,這樣的話就可以自定義了,你想使用什么樣的組件進行占位都行,同樣加載出錯的占位圖也是一個組件,也可以自己定義;該組件也是通過緩存來加載圖片的。

       new CachedNetworkImage(
        width: 120,
         fit: BoxFit.fitWidth,
         placeholder: new CircularProgressIndicator(),
         imageUrl: imageUrl,
         errorWidget: new Icon(Icons.error),
        )

    • 構造函數
        Image.network(
          String src, {
          Key key,
          double scale = 1.0,
          this.frameBuilder,
          this.loadingBuilder,
          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.filterQuality = FilterQuality.low,
          Map<String, String> headers,
        }) : image = NetworkImage(src, scale: scale, headers: headers),
             assert(alignment != null),
             assert(repeat != null),
             assert(matchTextDirection != null),
             super(key: key);
  • new Image.memory: 加載Uint8List資源圖片。
    • 用來將一個 byte 數組加載成圖片
      new Image.memory(bytes)
    • 命名構造函數
        Image.memory(
          Uint8List bytes, {
          Key key,
          double scale = 1.0,
          this.frameBuilder,
          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.filterQuality = FilterQuality.low,
        }) : image = MemoryImage(bytes, scale: scale),
             loadingBuilder = null,
             assert(alignment != null),
             assert(repeat != null),
             assert(matchTextDirection != null),
             super(key: key);
        

四,參數詳解

  • image
    從哪里加載圖片,值為一個 ImageProvider 對象,ImageProvider 的實現類有 AssetBundleImageProvider(AssetImage 繼承自它)、FileImageMemoryImageNetworkImage,需要注意的是,如果選擇 AssetImage 從資源目錄中加載圖片,需在 pubspec.yaml 配置文件中配置 assets 目錄:上面有介紹
  • width 和 heigh: 寬和高
  • alignment:

    如果圖片沒有填充滿容器的話,圖片的對齊方式,值為一個 AlignmentGeometry 對象,Alignment 是它的一個實現類,可選值同 ContainerAlignment 取值一樣。

        Alignment.topLeft:垂直靠頂部水平靠左對齊。
        Alignment.topCenter:垂直靠頂部水平居中對齊。
        Alignment.topRight:垂直靠頂部水平靠右對齊。
        Alignment.centerLeft:垂直居中水平靠左對齊。
        Alignment.center:垂直和水平居中都對齊。
        Alignment.centerRight:垂直居中水平靠右對齊。
        Alignment.bottomLeft:垂直靠底部水平靠左對齊。
        Alignment.bottomCenter:垂直靠底部水平居中對齊。
        Alignment.bottomRight:垂直靠底部水平靠右對齊。

     除了上面的常量之外,還可以創建 Alignment 對象指定 xy 偏移量。

  • color
    在圖片上設置顏色,值為一個 Color 對象,會覆蓋 image 指定的圖片,如果也設置了 colorBlendMode 屬性,則會與 image 混合產生特殊效果。
  • colorBlendMode
    • 顏色混合模式,類似 BoxDecorationbackgroundBlendMode

    • BlendModel枚舉值
    • switch (blendMode) {
      case kCGBlendModeNormal: {
        strMsg = @"kCGBlendModeNormal: 正常;也是默認的模式。前景圖會覆蓋背景圖";
         break;
      }
      case kCGBlendModeMultiply: {
         strMsg = @"kCGBlendModeMultiply: 正片疊底;混合了前景和背景的顏色,最終顏色比原先的都暗";
         break;
      }
      case kCGBlendModeScreen: {
         strMsg = @"kCGBlendModeScreen: 濾色;把前景和背景圖的顏色先反過來,然后混合";
         break;
      }
      case kCGBlendModeOverlay: {
         strMsg = @"kCGBlendModeOverlay: 覆蓋;能保留灰度信息,結合kCGBlendModeSaturation能保留透明度信息,在imageWithBlendMode方法中兩次執行drawInRect方法實現我們基本需求";
         break;
      }
      case kCGBlendModeDarken: {
         strMsg = @"kCGBlendModeDarken: 變暗"; //將線條色變為黑色,背景色設置為目的色
         break;
      }
      case kCGBlendModeLighten: {
         strMsg = @"kCGBlendModeLighten: 變亮";
         break;
      }
      case kCGBlendModeColorDodge: {
         strMsg = @"kCGBlendModeColorDodge: 顏色變淡";
         break;
      }
      case kCGBlendModeColorBurn: {
         strMsg = @"kCGBlendModeColorBurn: 顏色加深"; //線條顏色(原本)加深,背景色設置為目的色
         break;
      }
      case kCGBlendModeSoftLight: {
         strMsg = @"kCGBlendModeSoftLight: 柔光";
         break;
      }
      case kCGBlendModeHardLight: {
         strMsg = @"kCGBlendModeHardLight: 強光"; //全為目的色
         break;
      }
      case kCGBlendModeDifference: {
         strMsg = @"kCGBlendModeDifference: 插值";
         break;
      }
      case kCGBlendModeExclusion: {
         strMsg = @"kCGBlendModeExclusion: 排除";
         break;
      }
      case kCGBlendModeHue: {
         strMsg = @"kCGBlendModeHue: 色調";
         break;
      }
      case kCGBlendModeSaturation: {
         strMsg = @"kCGBlendModeSaturation: 飽和度";
         break;
      }
      case kCGBlendModeColor: {
         strMsg = @"kCGBlendModeColor: 顏色"; //感覺將圖片線條色設置為白色,背景色設置為目的色,之后再再圖片上加一個有透明度的目的色
         break;
      }
      case kCGBlendModeLuminosity: {
         strMsg = @"kCGBlendModeLuminosity: 亮度";
         break;
      }

      //Apple額外定義的枚舉
      //R: premultiplied result, 表示混合結果
      //S: Source, 表示源顏色(Sa對應透明度值: 0.0-1.0)
      //D: destination colors with alpha, 表示帶透明度的目標顏色(Da對應透明度值: 0.0-1.0)
      case kCGBlendModeClear: {
        strMsg = @"kCGBlendModeClear: R = 0"; //1.清空(如果圖標背景色為白色則為全白)
        break;
      }
      case kCGBlendModeCopy: {
        strMsg = @"kCGBlendModeCopy: R = S"; //2全色覆蓋整個圖片
        break;
      }
      case kCGBlendModeSourceIn: {
        strMsg = @"kCGBlendModeSourceIn: R = S*Da"; //3.線條變色
        break;
      }
      case kCGBlendModeSourceOut: {
        strMsg = @"kCGBlendModeSourceOut: R = S*(1 - Da)"; //4.背景變為目的色,線條自動變為白色(比如圖標線條原為藍色,會自動變為白色)
        break;
      }
      case kCGBlendModeSourceAtop: {
        strMsg = @"kCGBlendModeSourceAtop: R = S*Da + D*(1 - Sa)"; //5.線條變色,目前感覺和SourceIn效果一致
        break;
      }
      case kCGBlendModeDestinationOver: {
        strMsg = @"kCGBlendModeDestinationOver: R = S*(1 - Da) + D"; //6.背景色變為目的色,線條色不變
        break;
      }
      case kCGBlendModeDestinationIn: {
        strMsg = @"kCGBlendModeDestinationIn: R = D*Sa;能保留透明度信息"; //7.只看到線條色(本色),無其他顏色
        break;
      }  
      case kCGBlendModeDestinationOut: {
        strMsg = @"kCGBlendModeDestinationOut: R = D*(1 - Sa)"; //8.空白什么都沒喲
        break;
      }
      case kCGBlendModeDestinationAtop: {
        strMsg = @"kCGBlendModeDestinationAtop: R = S*(1 - Da) + D*Sa"; //9.會把整個矩形的背景填充目的色(如圖9系列)原色保留
        break;
      }
      case kCGBlendModeXOR: {
        strMsg = @"kCGBlendModeXOR: R = S*(1 - Da) + D*(1 - Sa)"; //10.線條變白,背景色變為目的色
        break;
      }
      case kCGBlendModePlusDarker: {
        strMsg = @"kCGBlendModePlusDarker: R = MAX(0, (1 - D) + (1 - S))"; //11.線條變為黑色, 背景色變為目的色
        break;
      }
      case kCGBlendModePlusLighter: {
        strMsg = @"kCGBlendModePlusLighter: R = MIN(1, S + D)(最后一種混合模式)"; //12.線條變為白色(混合色:如color為紅色,就是偏粉色的白,有一定透明度的感覺)
        break;
      }
      default: {
        break;
      }


    •   
  • excludeFromSemantics
    是否啟用圖像的語義描述。
  • filterQuality
    圖像過濾器的質量級別(使用該屬性還沒看到效果,后面用到了再研究)。
  • fit:

    圖片的縮放方式,類似 Android 中 ImageViewscaleType,可選值有:

       BoxFit.none:將圖片的內容按原大小居中顯示。
       BoxFit.contain:將圖片的內容完整居中顯示,通過按比例縮小或原來的 size 使得圖片寬/高等於或小於組件的寬/高,類似 Android 的 centerInside。
       BoxFit.cover:按比例放大圖片的 size 居中顯示,類似 Android 的 centerCrop。
       BoxFit.fill:把圖片不按比例放大/縮小到組件的大小顯示,類似 Android 的 fitXY。
       BoxFit.fitHeight:把圖片的高按照組件的高顯示,寬等比例放大/縮小。
       BoxFit.fitWidth:把圖片的寬按照組件的寬顯示,高等比例放大/縮小。
       BoxFit.scaleDown:如果圖片寬高大於組件寬高,則讓圖片內容完全居中顯示,此時同 contain,如果圖片寬高小於組件寬高,則按圖片原大小居中顯示,此時同 none。
  • centerSlice
      該屬性用於的中心拉伸,值為一個 Rect 對象,應該就是拉伸區域,我在使用該屬性的時候只有當 fit 設置為 contain 和 fill 時才看到了效果,該屬性應該也是用於圖形變換,不常用
    • 使用方法
      //centerSlice =  Rect.fromLTRB(l, t, r, b)

      Image.network(
        "https://upload.jianshu.io/users/upload_avatars/3884536/d847a50f1da0.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240",
          width: 400,
          height: 400,
          fit: BoxFit.contain,
          centerSlice: Rect.fromLTWH(10, 10, 10, 10),
      )

    • 效果  
      • Rect效果默認
         
      • centerSlice處理
         
          
  • gaplessPlayback(無間隙播放)

    • 當image provider 發生變化時,顯示新圖片的過程中,如果true則保留舊圖片直至顯示出新圖片為止;如果false,則顯示新圖片的過程中,空白,不保留舊圖片。

  • repeat:

    如果圖片沒填充滿容器的話,圖片的重復方式,可選值有:

    •  ImageRepeat.noRepeat:不重復。
    • ImageRepeat.repeat:X、Y 軸都重復。

    • ImageRepeat.repeatX:只在 X 軸重復。

    • ImageRepeat.repeatY:只在 Y 軸重復。

  • semanticLabel:
    圖像的語義描述,類似 Android 中 ImageView 的 contentDescription 屬性。

五,示例demo  

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
//  var imgUrl =
   //   "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1545191828292&di=caef0d773e90142191de9fc5f5871cef&imgtype=0&src=http%3A%2F%2Fimg.mp.sohu.com%2Fq_mini%2Cc_zoom%2Cw_640%2Fupload%2F20170807%2Fb008bbf3df1b490d85e3ff3152ea898e_th.jpg";
    var imgUrl =
        "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1545790666&di=45beff1e706ea81d796d2268553c9e6f&imgtype=jpg&er=1&src=http%3A%2F%2Fp1.music.126.net%2FfydScGuKzV4GFdqeCMKhxQ%3D%3D%2F109951163178133629.jpg%3Fparam%3D180y180";
    return MaterialApp(
      //是否顯示 debug 標簽
      debugShowCheckedModeBanner: false,
      title: "Image",
      home: Scaffold(
        appBar: new AppBar(
          title: new Text("Image"),
        ),
        body: new Container(
          color: new Color(0xFFFF0000),
          //子組件
          child: new Image(
            /**
             * 從資源目錄中加載圖片,需在 pubspec.yaml 配置文件中配置 assets 目錄
            * flutter:
            *  assets:
            *    - assets/images/
            * 必須是上面的層級關系,但是感覺從資源目錄加載圖片老有問題,有時候顯示不出來但又不報錯,可以試試目錄后面跟上具體文件名,即
            * flutter:
            *   assets:
            *    - assets/images/iverson.jpg
            * 但是這樣每張圖片都得配置,未免太過麻煩
            * image: new AssetImage("assets/images/iverson.jpg"),
            **/
            //從網絡加載圖片,非常容易,不用配置,而且只要有網就沒什么問題
            image: new NetworkImage(imgUrl),
            width: 300,
            height: 200,
            /*
            * 如果圖片沒有填充滿容器的話,圖片的對齊方式,值為一個 AlignmentGeometry 對象,Alignment 是它的一個實現類
            * 可選值同 Container 的 Alignment 取值一樣。
            * Alignment.topLeft:垂直靠頂部水平靠左對齊
            * Alignment.topCenter:垂直靠頂部水平居中對齊
            * Alignment.topRight:垂直靠頂部水平靠右對齊
            * Alignment.centerLeft:垂直居中水平靠左對齊
            * Alignment.center:垂直和水平居中都對齊
            * Alignment.centerRight:垂直居中水平靠右對齊
            * Alignment.bottomLeft:垂直靠底部水平靠左對齊
            * Alignment.bottomCenter:垂直靠底部水平居中對齊
            * Alignment.bottomRight:垂直靠底部水平靠右對齊
            * 除了上面的常量之外,還可以創建 Alignment 對象指定 x、y 偏移量
            * 
            */
           alignment: Alignment.center,
            //在圖片上設置顏色,值為一個 Color 對象,會覆蓋 image 指定的圖片,如果也設置了 colorBlendMode 屬性,則會與 image 混合產生特殊效果
           color: new Color(0xFFFFFF00),
            //顏色混合模式,類似 BoxDecoration 的 backgroundBlendMode
           colorBlendMode: BlendMode.darken,
           excludeFromSemantics: true,
           filterQuality: FilterQuality.high,
            /*
            * 圖片的縮放方式,類似 Android 中 ImageView 的 scaleType,可選值有:
            * BoxFit.none:將圖片的內容按原大小居中顯示。
            * BoxFit.contain:將圖片的內容完整居中顯示,通過按比例縮小或原來的 size 使得圖片寬/高等於或小於組件的寬/高,類似 Android 的 centerInside。
            * BoxFit.cover:按比例放大圖片的 size 居中顯示,類似 Android 的 centerCrop。
            * BoxFit.fill:把圖片不按比例放大/縮小到組件的大小顯示,類似 Android 的 fitXY。
            * BoxFit.fitHeight:把圖片的高按照組件的高顯示,寬等比例放大/縮小。
            * BoxFit.fitWidth:把圖片的寬按照組件的寬顯示,高等比例放大/縮小。
            * BoxFit.scaleDown:如果圖片寬高大於組件寬高,則讓圖片內容完全居中顯示,此時同 contain,如果圖片寬高小於組件寬高,則按圖片原大小居中顯示,此時同 none。
            */
            fit: BoxFit.contain,
            centerSlice:new Rect.fromCircle(center: Offset(100.0, 100.0), radius: 10.0),
            //當圖像提供者發生變化時,是繼續顯示舊圖像,默認不顯示
            gaplessPlayback: true,
            //圖片與顏色混合模式
            matchTextDirection: true,
            /*
            * 如果圖片沒填充滿容器的話,圖片的重復方式,可選值有:
            * ImageRepeat.noRepeat:不重復
            * ImageRepeat.repeat:X、Y 軸都重復
            * ImageRepeat.repeatX:只在 X 軸重復
            * ImageRepeat.repeatY:只在 Y 軸重復
            */
            repeat: ImageRepeat.noRepeat,
            //圖像的語義描述
            semanticLabel:'Image組件學習',
          ),
        ),
      ),
    );
  }
}

六,實現圓角/圓形圖片

  • 圓角

    • 使用裁剪來實現圖片圓角:
      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組件來實現。
  • 圓形
    圓形圖片用得最多的應該是頭像之類的,這種同樣有多種方式可以實現,下面我也舉兩個例子

    • 使用裁剪實現圓形圖片:
      new ClipOval(
          child: Image.network(
          imageUrl,
          scale: 8.5,
        ),
      )
    • 使用CircleAvatar來實現圓形圖片:
      new CircleAvatar(
        backgroundImage: NetworkImage(imageUrl),
        radius: 50.0,
      )

七,官方地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM