Flutter 127: 圖解基礎 Image 小組件

    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.noneBoxFit.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 案例源碼


    小菜對 Image 的學習還僅限於基礎應用,對於平時不常用的屬性有了進一步瞭解,但對源碼的學習還不夠深入;如有錯誤,請多多指導!

來源: 阿策小和尚

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章