• 【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,
           120,
          fit: BoxFit.fitWidth,
        )

        //第二种是加载一个透明的占位图,但是需要注意的是,这个组件是不可以设置加载出错显示的图片的
        new FadeInImage.memoryNetwork( placeholder: kTransparentImage, image: imageUrl, 120, fit: BoxFit.fitWidth, )

          //另一种方法可以使用第三方 package 的 CachedNetworkImage 组件:CachedNetworkImage 组件中的占位图是一个 Widget,这样的话就可以自定义了,你想使用什么样的组件进行占位都行,同样加载出错的占位图也是一个组件,也可以自己定义;该组件也是通过缓存来加载图片的。

         new CachedNetworkImage(
           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",
            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),
                 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(
           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,
        )

    七,官方地址

  • 相关阅读:
    StackOverFlow 最有影响力的IT书箱 [Share]
    Principles of Distributed Computing [Share]
    C/C++ 命令行参数
    函数指针
    coursera-北大-计算概论【已完成】
    有关宏定义一题
    blog.163.com 崩溃以后~
    一步步学习SPD2010--第十一章节--处理母版页
    一步步学习SPD2010--第十章节--SP网站品牌化(12)--关键点
    一步步学习SPD2010--第十章节--SP网站品牌化(11)--使用CSS报表
  • 原文地址:https://www.cnblogs.com/lxlx1798/p/11060601.html
Copyright © 2020-2023  润新知