android -- 重新认识ImageView的几种ScaleType
前言
最近项目里出现了个图片显示的小问题,就是类似朋友圈的这种,需求是图片只能有一张,并且这张图片来自屏幕截图(支持截长图),所以涉及到长图的展示,github 上有一些开源库,大致原理是利用 BitmapRegionDecoder 把长图切成n个小图展示,因为不想引用那么多第三方代码,项目需求也没说要加手势什么的并且只有一张图片,当然,还有懒,然后自己就想了个简单的方案:ScrollView 里嵌套 imageView。让 ImageView 宽和高自适应。因为测试的机型屏幕大小都差不多,所以当时并未发现什么问题,当上线后,有客户反映,有的图片显示不全(被放大裁剪了)。最后研究是图片展示格式的问题。
what–具体问题
因为发现是在某些小屏幕手机上有些图片显示不完整,在屏幕大的手机上就不会。
显然,如果图片本身宽高大于手机屏幕宽高,图片就被截取了,所以用户就看不到完整的图片,并且显示图片被放大了,所以可以首先猜想一下是图片显示格式的问题。
why–问题原因
要想明白问题是如何产生的,首先我们看看 ImageView 显示的几种 ScaleType。
官方文档对它是这样解释的:”Options for scaling the bounds of an image to the bounds of this view”
借用 encienqi 的翻译:控制图片如何 resized/moved 来匹对 ImageView 的 size。
ImageView.ScaleType 是个枚举类型,共有 8 种取值
ImageView.ScaleType | 含义 |
---|---|
CENTER | 按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示(不进行缩放) |
CENTER_CROP | 按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长(宽) |
CENTER_INSIDE | 将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽 |
FIT_CENTER | 使用Matrix.ScaleToFit中CENTER方式缩放图像 |
FIT_END | 使用Matrix.ScaleToFit中END 方式缩放图像 |
FIT_START | 使用Matrix.ScaleToFit中START方式缩放图像 |
FIT_XY | 使用Matrix.ScaleToFit中FILL方式缩放图像 |
MATRIX | 用矩阵来绘制,动态缩小放大图片来显示 |
其中的 Matrix.ScaleToFit 的作用:控制 src rect 应该如何对齐到 setRectToRect() 的 dst rect 。有以下几种取值:
Matrix.ScaleToFit | 含义 |
---|---|
CENTER | 把图片按比例扩大/缩小到View的宽度,居中显示 |
END | 把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置 |
START | 把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置 |
FILL | 把图片扩大/缩小到View的大小显示,不按图片比例 |
光看文字好像看不出什么区别来,下面放一波图,对比一下,效果立即就出来了:
图中代码里获取到屏幕尺寸及图片尺寸( dp 单位),下面三个 ImageView 的宽高分别为 50 dp ,wrap_content , 200 dp (也就是图片比 ImageView 小,自适应,大 这三种情况),为了效果显示,ImageView 背景为黑色。
其中是否对图片进行缩放、当图片大小大于 ImageView 时图片是否被裁剪(显示不完整)、如果有缩放是否按原图宽高比等情况可以看图大致总结一下:
ImageView.ScaleType | 缩放 | 保持原图比例 | 裁剪 |
---|---|---|---|
CENTER | N | Y | Y |
CENTER_CROP | Y | Y | Y |
CENTER_INSIDE | Y | Y | N |
FIT_CENTER | Y | Y | N |
FIT_END | Y | Y | N |
FIT_START | Y | Y | N |
FIT_XY | Y | N | N |
MATRIX | N | Y | Y |
how–知道了原理,我们来解决问题
首先,之前一个突出问题是图片被裁剪了,但是需求不允许这样做,因为被裁剪的地方可能包含重要信息。
而我之前的做法,是把 ImageView 的 ScaleType 设置为 center_crop 的,对照上表,嗯,是会被裁剪的。
然后其中的 fit_start , fit_end 位置有点不太满足需求,而 fit_xy 不安原图比例。所以可以选择f it_center 或者 center_inside.
注意:因为我项目里 imageView 的宽高设的是自适应的,所以有这几种选择,如果是定值,那么还要自行分析。
最后,看似简单的问题,如果不理解原理,修改的时候东一榔头西一棒子,即使碰对了,后面再有问题,也不好及时定位。
demo地址:demo