图片框架

[toc]

图片框架

思维脑图:请点击查看图片框架.xmind

流程图:请点击查看图片框架.graffle

一、图片优化

1、图片占位图、异常图

2、图片加载动画

可适当在图片视图本身加入loading动画

3、图片缓存

3.1、直接图片视图加载

3.2、先加载图片数据,再赋值到图片视图上

3.3、去除多余的图片切换动画

4、降低图片质量(缩略图/数据万象)

4.1、使用缩略图

让后台返回缩略图地址,而不是大图地址

4.2、图片数据万象及其优化\根据视图大小,获取保持比例的合适目标图片(完整图)

后台不是给缩略图地址的情况下,自己通过图片地址,配置对应的参数,来展示。

图片数据万象的优化,请继续查看下文 数据万象/根据视图大小,获取保持比例的合适目标图片(完整图))

二、数据万象/根据视图大小,获取保持比例的合适目标图片(完整图)

1、背景

在服务端,我们保存的是图片的原图。但实际在app使用过程中,我们常常只需要该图的缩略图。那么如何及合理的得到我们想要的缩略图呢?

2、改进前

2.1、方法

缩略图的获取,最基本的方法是使用数据万象提供的接口,通过为其添加尺寸参数,即可得到缩略图片。

添加后的缩略图地址形如:https://www.demo.com/1.jpg?width=44&height=44

2.2、存在的问题

使用上述方法,我们虽然得到了自适应每个image图片视图自身大小的缩略图。

但同时也引入了另一个问题:就是如果某张图需要出现在不同大小的image视图中,则我们会下载及缓存多份数据。这无形中增加了①流量的消耗、②手机存储空间的消耗;③同时也因为认为要下载新缩略图,而导致无法使用就近的缩略图。所以我们需要改进。

示例:

1
2
3
4
5
6
优化前:在 44*44 和 50*50 大小的视图区域上的图片地址分别如下:
https://www.demo.com/1.jpg?width=44&height=44
https://www.demo.com/1.jpg?width=50&height=50

优化后:两个区域统一为使用 64 * 64 大小的视图区域上的图片地址,从而如果避免获取到太多份不同大小的同图?
https://www.demo.com/1.jpg?width=64&height=64

3、改进后

3.1、改进方法

改进方式,在进行万象拼接前,我们通过提前新增缩略图梯度,将相近大小的缩略图归为使用同一张。

梯度的层数,可根据自己实际项目图片规范设计。

举例:以宽为 375pt 的手机屏幕为例。假设你图片规范是 [ 64pt 、188pt、375pt ]。

则当你的视图是 100pt 和 120pt 的视图都使用 188pt 的图片。

3.2、改进的好处

通过上述方法,我们能够达到①减少流量的消耗、②减少手机存储空间的消耗;③同时使得对于同一图片在相近大小的image图片视图的地方,由于计算出的缩略图处在同一梯度,而可以不用重新下载等待,而是直接使用缓存渲染,从而大大提升了用户体验。

4、流程

4.1、主要流程

获取梯度范围 -> 完成万象拼接

4.2、主要流程图

以下为”获取梯度范围”的流程

image-20230531212509071

图片的更多完整流程图,请查看 图片框架.graffle

三、图片高磁盘占用的排查与优化

文档:《高磁盘占用的排查与优化.md

四、图片展示

1、竖直滚动列表上的图片展示

2、图片大图浏览

image-20240725230554593

图片来源:图片框架.xmind

附1:图片优化的相关代码

1、图片占位图、异常图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
return CachedNetworkImage(
width: width,
height: height,
fit: fit,
imageUrl: imageUrl,
placeholder: placeholder,
errorWidget: (context, url, error) {
if (this.errorWidget != null) {
return this.errorWidget(context, url, error);
} else {
return Container();
}
},
);

2、图片加载动画

可适当在图片视图本身加入loading动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
return CachedNetworkImage(
width: width,
height: height,
fit: fit,
imageUrl: imageUrl,
placeholder: placeholder,
errorWidget: (context, url, error) {
if (this.errorWidget != null) {
return this.errorWidget(context, url, error);
} else {
return Container();
}
},
placeholderFadeInDuration: placeholderFadeInDuration,
fadeOutDuration: fadeOutDuration,
fadeInDuration: fadeInDuration,
progressIndicatorBuilder: (context, url, progress) {
if (this.progressIndicatorBuilder != null) {
return this.progressIndicatorBuilder(context, url, progress);
} else {
return Container(color: Color(0xFFF0F0F0));
}
},
);

3、图片缓存

3.1、直接图片视图加载

1
2
3
4
5
TolerantNetworkImage(
imageUrl: networkUrl,
width: 100,
height: 300,
)

3.2、先加载图片数据,再赋值到图片视图上

eg:首页频道图片切换

1
2
3
4
5
6
7
8
9
10
11
12
13
// 定义
ImageProvider imageProvider_network;

// 生成数据
imageProvider_network = CachedNetworkImageProvider(networkUrl);

// 使用数据
return Image(
image: imageProvider_network,
width: 100,
height: 300,
fit: BoxFit.cover,
);

3.3、去除多余的图片切换动画

eg:许个愿图片切换

1
2
3
4
5
6
7
8
9
10
11
12
return CachedNetworkImage(
width: width,
height: height,
fit: fit,
imageUrl: imageUrl,
placeholderFadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
fadeInDuration: Duration.zero,
progressIndicatorBuilder: (context, url, progress) {
return Container(color: Color(0xFFF0F0F0));
},
);

End