[番外]-Flutter小課堂-Image篇

張風捷特烈發表於2019-07-09
前言

圖片是一個我們又愛又恨的東西,它是完美之本,也是萬惡之源
為闡述清楚Image的使用,專開本文,希望通過本文,你可以學到一個很有用的方法
另外通過最後佈局海賊王的懸賞令,基本實現可改頭像,名字,懸賞的效果,可縮放

[番外]-Flutter小課堂-Image篇


1.Image的簡單認識

1.1:Image的屬性

首先Image作為元件存在於widgets/image.dart,dart.ui裡也有個Image類,別導錯了
其次,Image作為一個有狀態的元件,繼承自StatefulWidget ,所有屬性如下:

class Image extends StatefulWidget {
  const Image({
    Key key,
    @required this.image,
    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);

  final ImageProvider image;
  final double width;
  final Color color;
  final BlendMode colorBlendMode;
  final BoxFit fit;
  final AlignmentGeometry alignment;
  final ImageRepeat repeat;
  final Rect centerSlice;
  final bool matchTextDirection;
  final bool gaplessPlayback;
  final String semanticLabel;
  final bool excludeFromSemantics;
複製程式碼

1.2.Image物件的建立

根據不同需求,一共有五種建立Image元件物件的方法

const Image({Key key,@required this.image,//通過ImageProvider建立
Image.network( String src, {//通過網路資源建立
Image.file(File file, { //通過檔案建立
Image.asset(String name, //通過資原始檔建立
Image.memory(Uint8List bytes, //通過記憶體建立
複製程式碼

1.3:資源圖片的訪問

Image.asset中有一大段註釋介紹如何flutter中使用資源圖片

[番外]-Flutter小課堂-Image篇

var img = Image.asset(
  'images/icon_head.png',
  width: 50,
  height: 50,
);
複製程式碼

1.4:Image的狀態

Image是一個有狀態的元件,這點確實出乎我意料,我們看看他的狀態有哪些

class _ImageState extends State<Image> {
  ImageStream _imageStream;
  ImageInfo _imageInfo;
  bool _isListeningToStream = false;
  bool _invertColors;
複製程式碼

2.Image的屬性表現

2.1:Image的寬高

將圖片放在3:2的圖片放在一個200*200的容器裡,表現效果如下

[番外]-Flutter小課堂-Image篇

var img = Image.asset(
  'images/ls.jpg',
  width: 100,
  height: 100,
);

var imgContainer=Container(
  width: 200,
  height: 200,
  color: Colors.cyanAccent,
  child: img,
);
複製程式碼

其中可以看出:
1.預設情況下影象會顯示完全
2.這裡Container定義的長寬,可見Image的長寬是無效的
3.Image元件佔據的佈局空間並非僅是圖片!


2.2: 圖片的適應模式:fit

為了方便對比,這裡寫了一個方法批量生成,可以看出各種模式的特性。

var fitMode = [BoxFit.none, BoxFit.contain, BoxFit.cover,
  BoxFit.fill, BoxFit.fitHeight, BoxFit.fitWidth, BoxFit.scaleDown
];

//迴圈生成Image控制元件
form() {
  var imgLi = <Widget>[];
  fitMode.forEach((fit) {
    var img = Container(
        margin: EdgeInsets.all(10),
        width: 150,
        height: 60,
        color: randomRGB(),
        child: Image(
          image: AssetImage("images/ls.jpg"),
          fit: fit,
        ));

    imgLi.add(Column(
      children: <Widget>[img, Text(fit.toString())],
    ));
  });
  return imgLi;
}

var imgBox = Wrap(
  children: form(),
);

Color randomRGB() {
  Random random = new Random();
  int r = 30 + random.nextInt(200);
  int g = 30 + random.nextInt(200);
  int b = 30 + random.nextInt(200);
  return Color.fromARGB(255, r, g, b);
}
複製程式碼
  • 寬高比2:3測試結果:

[番外]-Flutter小課堂-Image篇

  • 寬高比3:2測試結果:

[番外]-Flutter小課堂-Image篇

  • 圖片小於容器尺寸下的測試結果

[番外]-Flutter小課堂-Image篇

根據圖片看一下,應該不言而喻了。


2.3:顏色以及混合模式:color,colorBlendMode

同樣,也是批量測試一下,一圖勝千言,而且感覺高大上一點
這裡使用綠色和頭像進行疊合,效果如下:

[番外]-Flutter小課堂-Image篇

//混合模式陣列
var colorBlendMode = [
  BlendMode.clear,BlendMode.src,BlendMode.dst,
  BlendMode.srcOver,BlendMode.dstOver,BlendMode.srcIn,
  BlendMode.dstIn,BlendMode.srcOut,BlendMode.dstOut,
  BlendMode.srcATop,BlendMode.dstATop,BlendMode.xor,
  BlendMode.plus, BlendMode.modulate,BlendMode.screen,
  BlendMode.overlay,BlendMode.darken,BlendMode.lighten,
  BlendMode.colorDodge,BlendMode.colorBurn,BlendMode.hardLight,
  BlendMode.softLight,BlendMode.difference,BlendMode.exclusion,
  BlendMode.multiply,BlendMode.hue,BlendMode.saturation,
  BlendMode.color, BlendMode.luminosity,
];

//迴圈生成Image控制元件
formImgsColorBlendMode() {
  var imgLi = <Widget>[];
  colorBlendMode.forEach((mode) {
    var img = Container(
        margin: EdgeInsets.all(5),
        width:60,
        height: 60,
        child: Image(
          image: AssetImage("images/icon_head.png"),
          color: Colors.blue,
          colorBlendMode: mode,
        ));
    imgLi.add(Column(children: <Widget>[
      img,
      Text(mode.toString().split(".")[1])
    ]));
  });
  return imgLi;
}

var imageColorMode = Wrap(
  children: formImgsColorBlendMode(),
);
複製程式碼

如果以後有什麼需要類比的模式,列舉什麼的,都可以通過這種方式批量生成,效果又好又省事。


4. 對齊屬性:alignment

有9個靜態常量,分別是九個方位,另外也可以通過Alignment的構造方法來進行對齊偏移

[番外]-Flutter小課堂-Image篇

var alignments = [
  Alignment.center,  Alignment.centerLeft, Alignment.centerRight,
  Alignment.topCenter,Alignment.topLeft, Alignment.topRight,
  Alignment.bottomCenter,Alignment.bottomLeft,Alignment.bottomRight,
Alignment(0.01,0.01),Alignment(0.5,0.5)
];

//迴圈生成Image控制元件
formImgAlignments() {
  var imgLi = <Widget>[];
  alignments.forEach((align) {
    var img = Container( 
        margin: EdgeInsets.all(7),
        width: 150,
        height: 60,
        color: randomRGB(),
        child: Image(
          image: AssetImage("images/wy_300x200_little.jpg"),
          alignment: align,
        ));

    imgLi.add(Column(
      children: <Widget>[img, Text(e.toString())],
    ));
  });
  return imgLi;
}

var imageAlignments = Wrap(
  children: formImgAlignments(),
);

複製程式碼

2.5.重複模式:repeat

一目瞭然,不多說

[番外]-Flutter小課堂-Image篇

var repeats = [
  ImageRepeat.repeatY,  ImageRepeat.repeatX,
  ImageRepeat.noRepeat,ImageRepeat.repeat
];
//迴圈生成Image控制元件
formImgRepeat() {
  var imgLi = <Widget>[];
  repeats.forEach((repeat) {
    var img = Container(
        margin: EdgeInsets.all(7),
        width: 150,
        height: 90,
        color: randomRGB(),
        child: Image(
          image: AssetImage("images/wy_300x200_little.jpg"),
          repeat: repeat,
        ));

    imgLi.add(Column(
      children: <Widget>[img, Text(repeat.toString())],
    ));
  });
  return imgLi;
}

var imageRepeats = Wrap(
  children: formImgRepeat(),
);
複製程式碼

1.5:縮放質量:filterQuality

原始碼上說: 使用FilterQuality.low在縮放圖片時使用二次線性插值演算法
FilterQuality.none 在縮放圖片時使用臨近演算法
FilterQuality.hight 是最好的,也是最慢的,通常是三次插值或更好
FilterQuality.medium 的速度介於low和hight之間,通常是二次線性插值和錐體引數預濾波(mipmaps)的結合。
講得挺高大上,但用起來感覺也就那回事,hight確實要比none感覺好

[番外]-Flutter小課堂-Image篇

var qualitys = [
  FilterQuality.none,FilterQuality.high, 
  FilterQuality.medium, FilterQuality.low,

];
//迴圈生成Image控制元件
formImgQualitys() {
  var imgLi = <Widget>[];
  qualitys.forEach((q) {
    var img = Container(
        margin: EdgeInsets.all(7),
        width:110.0*3/2,
        height: 110,
        color: randomRGB(),
        child: Image(
          image: AssetImage("images/wy_300x200.jpg"),
          filterQuality: q,
        ));

    imgLi.add(Column(
      children: <Widget>[img, Text(q.toString())],
    ));
  });
  return imgLi;
}

var imageQualitys = Wrap(
  children: formImgQualitys(),
);
複製程式碼

3.每日一佈局:海賊王懸賞令

暫時沒有抽成自定義元件。這裡不分析了,有興趣的小夥伴自己看看,也可以自定義個元件玩玩。

[番外]-Flutter小課堂-Image篇

    const double viewRate = 0.663306; //檢視寬高比
    const double imgRate = 1.234411;//圖片寬高比
    var width =300.0;
    double height = width/viewRate;

    var textWanted= Text('WANTED',
       style: TextStyle(
           fontWeight: FontWeight.bold,
           letterSpacing:width/30,
           fontSize: width/6),
    );

    var name =Text('NA MI',
      style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: width/9),
    );

    var price= Text('16,000,000',
      style: TextStyle(
          letterSpacing:width/45,
          fontWeight: FontWeight.bold,
          fontSize: width/10),
    );
    var img =Container(
      decoration: BoxDecoration(
        border: Border.all(color: Colors.black,width: width/100),
      ),
      width: width,
      height: width/imgRate,
      child: Image.asset('images/娜美.jpg',fit: BoxFit.cover,),
    );

    var bottom =Stack(
      children: <Widget>[
        Image.asset('images/bottom.jpg',fit: BoxFit.fitWidth,),
        Container(child: name,alignment: Alignment.topCenter,padding: EdgeInsets.only(top: 6*width/100),),
        Container(child: price,alignment: Alignment.topCenter,padding: EdgeInsets.only(top: 17*width/100),)
      ],);
    var wanted = Container(
      width: width,
      height: height,
      color: Color(0xffded0b5),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[textWanted,Padding(padding:
        EdgeInsets.fromLTRB(5*width/100,0,5*width/100,5*width/100),child: img,),
          bottom
        ],),
    );
    var result=Card(child:wanted ,elevation: 5*width/100,);//最終元件
複製程式碼

本文到此接近尾聲了,如果想快速嚐鮮Flutter,《Flutter七日》會是你的必備佳品;如果想細細探究它,那就跟隨我的腳步,完成一次Flutter之旅。
另外本人有一個Flutter微信交流群,歡迎小夥伴加入,共同探討Flutter的問題,本人微訊號:zdl1994328,期待與你的交流與切磋。

相關文章