Flutter中的Image入门讲解

栏目: Android · 发布时间: 6年前

内容简介:图片常用的格式主要有图片加载到内存中的时候,假如是压缩格式则会解压缩,并占用上图中memory中所占用的内存。本文的一些内容会涉及到这些简单的知识,有兴趣的同学可以上网寻找更多资料。安卓开发者应该都知道Android中并不是天生支持gif和webp动图,但是这一特性在flutter中被很好的支持了。放一张官方的图:

图片常用的格式主要有 bmp,jpg,png,gif,web 等。图片也是一种二进制文件,每种格式的图片都由固定的头信息和真实数据块组成。图片原始数据一般从2byte-4byte。

type bits memory
ARGB_8888 32 4*W*H
ARGB_4444 16 2*W*H
RGB_565 16 2*W*H
ALPHA_8 8 1*W*H

图片加载到内存中的时候,假如是压缩格式则会解压缩,并占用上图中memory中所占用的内存。本文的一些内容会涉及到这些简单的知识,有兴趣的同学可以上网寻找更多资料。

安卓开发者应该都知道Android中并不是天生支持gif和webp动图,但是这一特性在flutter中被很好的支持了。放一张官方的图:

Flutter中的Image入门讲解

flutter的图像处理是在engine中完成的,但是这个引擎提供的接口都是最基本的图片信息,如何根据设定的属性展示到屏幕上是在flutter中完成的。

在engine中的 ./lib/ui/painting/codec.cc 文件中展示了调用dart代码的资源:

static sk_sp<SkImage> DecodeImage(fml::WeakPtr<GrContext> context,
                                  sk_sp<SkData> buffer,
                                  size_t trace_id)
复制代码

这个方法用于生成一个SkImage,并将主要属性映射到flutter中的 ui.Image 类中。这个ui.Image就是可以直接通过canvas渲染到屏幕上的数据了。

常见控件

flutter提供了丰富的控件库,但是我们首先要搞清楚一个原理,所有的widget并不是直接绘制图片的,而是控制的图片的主要属性的容器,负责绘制的是RenderObject,他们中间是通过ElementTree来联系起来。有了这个基础后,所有的widget都不会提供画布(canvas)来直接绘制image,所以在任何一个Widget源码中都不会提供绘制的代码。来看一下主要的Widget:

1. RawImage

这是一个最基础图片容器Widget。它能直接将原始图片呈现到屏幕上,并且有一些列的属性可供操作:

const RawImage({
    Key key,
    this.image,
    this.width,
    this.height,
    this.scale = 1.0,
    this.color,
    this.colorBlendMode,
    this.fit,
    this.alignment = Alignment.center,
    this.repeat = ImageRepeat.noRepeat,
    this.centerSlice,
    this.matchTextDirection = false,
    this.invertColors = false,
    this.filterQuality = FilterQuality.low,
  }) : assert(scale != null),
       assert(alignment != null),
       assert(repeat != null),
       assert(matchTextDirection != null),
       super(key: key);
复制代码

其中image类型就是上边提到的 ui.Image ,这个数据的获取官方推荐通过ImageStream添加listener来获取。

  • color和colorBlendMode

这两个属性可以做出许多的效果。

Flutter中的Image入门讲解

看一段简单的代码

class _MyHomePageState extends State<MyHomePage> {
  ImageInfo info;//图片信息
  List<BlendMode> blendModes = BlendMode.values;//所有的混合模式转换为list

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    Image.asset("images/yuan.png")
        .image
        .resolve(createLocalImageConfiguration(context))
        .addListener((ImageInfo image, bool synchronousCall) {
      setState(() {
        info = image; //刷新状态
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GridView.builder(
        itemCount: blendModes.length - 1,
        padding: EdgeInsets.only(top: 10.0),
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 4,
        ),
        itemBuilder: getItemBuilder,
      ),
    );
  }

  Widget getItemBuilder(BuildContext context, int index) {
    return Column(
      children: <Widget>[
        RawImage(
          image: info?.image,
          color: Colors.red,
          width: 40,
          height: 40,
          colorBlendMode: blendModes[index + 1],
          fit: BoxFit.cover,
        ),
        Container(
          padding: EdgeInsets.only(top: 10.0),
          child: Text(
            blendModes[index + 1].toString().split("\.")[1],
            style: TextStyle(
              color: Colors.black,
              fontSize: 15.0,
            ),
          ),
        ),
      ],
    );
  }
}
复制代码

flutter中的混合模式是枚举类型,和Android中的图片混合模式画笔混合模式基本保持一致。上面的代码描述了所有的混合模式并配有图,除了clear没有在里边(clear模式会清除所有内容)。image是一个简单的图片,带透明通道的绿色的圆,在图中就是dst模式下的样子,背景是一个纯红色,在图中就是src模式下的样子。

  • fit属性使用的是Boxfit的枚举值,看一下效果:

  • fill

填充,忽略原有的宽高比,填满为止

Flutter中的Image入门讲解
  • contain

包含,不改变原有比例让容器包含整个图片,容器多余部分填充背景

Flutter中的Image入门讲解
  • cover

覆盖,不改变原有比例,让图片充满整个容器,图片多余部分裁剪 ///

Flutter中的Image入门讲解
  • fitWidth

横向图片填充

Flutter中的Image入门讲解
  • fitHeight

纵向图片填充

Flutter中的Image入门讲解
  • none

原始大小居中

Flutter中的Image入门讲解
  • scaleDown

图片大小小于容器事相当于none,图片大小大于容器时缩小图片大小实现contain

Flutter中的Image入门讲解

centerSlice属性专门用于nine-patch文件。

其他属性暂时不讲。

一般情况下这个控件很少使用,但是他是其他Image控件的实现基础,所以必须要拎出来讲一下。

Image

这是一个通用包装类,它包装了RawImage,同时提供了一些简便的 Named constructors 来使用AssetsImage,ExactAssetImage等ImageProvider的子类。

  • Image , 从ImageProvider来获取图片显示

这个类的使用基本和RawImage一致,在使用的时候只是将参数 ui.Image 包装为了 ImageProvider ,不用再自己监听ImageStream。典型简单用法:

Widget image = Image(AssetImage("images/yuan.png"))
复制代码
  • Image.asset , 从Asset资源中获取图片显示

这个方法是 ImageProviderAssetImage 的简单用法:

Widget image = Image.asset("images/yuan.png")
复制代码
  • Image.network , 从URL获取网络图片显示

这个方法是 ImageProviderNetworkImage 的简单用法:

Widget image = Image.network("http://img.rangaofei.cn/01b18.jpg")
复制代码
  • Image.file , 从文件中获取图片显示

这个方法是 ImageProviderFileImage 的简单用法:

Widget image = Image.file(file)
复制代码
  • Image.memory 从内存中获取图片显示.

这个方法是 ImageProviderMemoryImage 的简单用法:

Widget image = Image.memory(byteList)
复制代码

CircleAvatar

主要用来显示用户的头像,任何图片都会被剪切为圆形。

一个简单用法:

CircleAvatar(
          child: Text("头像"),
          backgroundImage: AssetImage("images/yuan.png"),
          backgroundColor: Colors.red,
          radius: 50.0,
        ),
复制代码

生成的图像如下:

Flutter中的Image入门讲解

CircleAvatar 内置了许多的功能。randius用来控制图片的大小,同时它可以自动感知当前theme是白天模式还是夜间模式来切换图片颜色,另外它实际是包装了 AnimatedContainer ,设置的动画时间是200ms。在改变它的一些相关属性时会自动使用动画来执行。看一个简单的动图:

Flutter中的Image入门讲解

代码如下:

class _MyHomePageState extends State<MyHomePage> {
  double radius = 10.0;

  @override
  void initState() {
    super.initState();
    Future<Duration>.delayed(Duration(milliseconds: 2 * 1000), () {
      setState(() {
        radius = 20.0;
      });
      return Duration(milliseconds: 210);
    }).then((Duration d) {
      Future<Duration>.delayed(d, () {
        setState(() {
          radius = 40.0;
        });
        return Duration(milliseconds: 210);
      }).then((Duration d) {
        Future<Duration>.delayed(d, () {
          setState(() {
            radius = 30.0;
          });
        });
      });
      ;
    });
  }

  @override
  Widget build(BuildContext context) {
   
    return Scaffold(
      body: Center(
        child: CircleAvatar(
          child: Text("头像"),
          backgroundImage: AssetImage("images/yuan.png"),
          radius: radius,
        ),
      ),
    );
  }
}
复制代码

这里我并没有使用AnimationController来控制radius值的变化,而是通过一个延时来控制。初始化的时候radius是10.0,延迟两秒后变为20.0,因为CircleAvatar默认的过度时间是200ms,为了有一个平滑的国度效果,我把下一次改变时间设置为了210ms,这时半径是40.0,最后经过210ms后半径设置为30.0,整个变化过程为:

10->20->40->30
复制代码

DecorationImage

主要用于 BoxDecoration 中的image属性,可以讲图片展示为boxdecoration。这里不做详细解释。

Widget getBoxImage() {
    return Container(
      decoration: BoxDecoration(
          image: DecorationImage(image: AssetImage("images/yuan.png"))),
    );
  }
复制代码

这个并不是一个Widget,只能用在BoxDecoration

Ink.image

同样很简单,用于显示一张图片。 这里相当于Ink一个简单写法,这个Ink控件里边只有decoration.image属性的话,可以直接替代Ink。

Widget getInkedImage() {
    return Ink.image(image: AssetImage("images/timg.jpeg"));
  }
复制代码

ImageIcon

基本和上边的一致效果:

Widget getImageIcon() {
    return ImageIcon(AssetImage("images/timg.jpeg"));
  }
复制代码

FadeInImage

占位图渐变动画控件,这个控件在加载网络图片时经常用到。主要作用是在加载网络图片这个耗时操作时显示一个占位图,并在获取到网络图片时以alpha动画来做出一个淡入淡出的效果。

看一下效果图

Flutter中的Image入门讲解

但是这个并不是一个银弹,在加载单帧图片时确实可以达到很好的效果,但是在加载网络图片时会丢失显示plcaceholder淡出时的所有帧,同样在网络图片错误时并不会有错误的占位图,而是直接抛出异常。这里不详细解释了。

Image的加载过程

上边介绍了一些基本的Image控件,这些都是属于Widget层使用的,但是他们的主要依赖都是 ImageProvider ,我们可以通过订制 ImageProvider 来实现自己的加载方式。

具体流程如图

Flutter中的Image入门讲解

在解析出来的ImageInfo中可以通过 Future<ByteData> toByteData({ImageByteFormat format: ImageByteFormat.rawRgba}) 方法改变ImageByte的数据格式:

  1. rawRgba,未解码的byte,每个通道占8bit
  2. rawUnmodified,未解码且为修改的byte,例如灰度图
  3. png,最常见的无损数据格式

这里有我做的一个控件来控制gif的加载速度:

Flutter中的Image入门讲解

最后附上源码:

github.com/rangaofei/s…

初学者,还有我做的一个简单的包:

pub.flutter-io.cn/packages/sa…


以上所述就是小编给大家介绍的《Flutter中的Image入门讲解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

标签: flutter image

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Practice of Programming

The Practice of Programming

Brian W. Kernighan、Rob Pike / Addison-Wesley / 1999-2-14 / USD 49.99

With the same insight and authority that made their book The Unix Programming Environment a classic, Brian Kernighan and Rob Pike have written The Practice of Programming to help make individual progr......一起来看看 《The Practice of Programming》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具