前言
在 Android 开发中,假如咱们不确定图片的宽高,又想让 ImageView
以固定的宽度或高度显现,且图片宽高比保持不变,咱们很容易想到 adjustViewBounds
这个属性,合作固定的 ImageView
宽度或高度,即可实现宽/高固定,另一边自适应。
原因
有一个即时通讯产品,Emoji 表情经过服务端接口下发资源,支持动态增删,一起本地有一份兜底数据,用于网络不可用时的兜底展现。有一天产品在后台新增了几个表情,测验发现个别手机上新上的表情显现比较小,而本地兜底的表情则显现正常。
这儿的表情面板运用 RecyclerView
实现,Emoji Item 运用 RelativeLayout
作为容器,Emoji 图片运用 ImageView
固定高度,经过 adjustViewBounds
使宽度根据图片宽高比自适应展现。
复现
排查进程比较弯曲,这儿直接测验复现。
新建一个布局文件,加入一个 ImageView
,高度固定150dp,大于图片高度,设置 adjustViewBounds
为 true
嗯,没什么问题,图片被等比例拉伸,ImageView
的宽度也自适应了,契合对 adjustViewBounds
的预期。
接下来,在 ImageView
外层嵌套一层 RelativeLayout
WTF! 意想不到的工作发生了,图片没有按照预期的宽高比进行拉伸,只是展现了本来的尺度,就好像 adjustViewBounds
历来都不存在一样!
原因
先看一下 ImageView
的丈量办法,为了便利阅读,代码做了简化。
ImageView
的丈量并不杂乱,大致能够分为以下几步:
- 判断是否设置
adjustViewBounds
,假如设置,持续往下,不然运用常规丈量办法(即运用Drawable
宽高、最小宽高和background
宽高的最大值) - 根据丈量形式判断是否能够调整宽度或高度,假如能够,持续往下,不然运用常规丈量办法
- 取得
Drawable
宽高和 View 最大宽高的最小值,得到实践宽高比,判断实践宽高比和Drawable
是否相同,假如相同,则运用当时宽高,丈量完毕,不然持续 - 根据
Drawable
宽高比调整实践宽高,运用调整后的宽高作为丈量结果,丈量完毕
并没有看出什么端倪,看来问题或许不在 ImageView
这儿,那就只剩 RelativeLayout
这个“嫌疑人”了。
持续查看 RelativeLayout
的丈量办法。
RelativeLayout
的丈量办法就杂乱多了,这儿摘出要害代码
能够看出,RelativeLayout
会对子 View 丈量两次,第一次丈量水平方向,确定子 View 的宽度,第2次,运用前次丈量的宽度,再次丈量,得到子 View 实践的尺度。
这儿没看出什么问题,持续看 measureChildHorizontal
办法
本相终于浮出眼前!
留意看14-18行,在确定高度丈量形式时,假如高度是 MATCH_PARENT
,则运用 EXACTLY
形式,不然运用 AT_MOST
形式。
因为咱们 ImageView
是固定高度,即固定值,因而会运用 AT_MOST
形式进行丈量,而宽度也是
AT_MOST
,回想一下上面 ImageView
的丈量办法,假如宽高都是 AT_MOST
,则实践巨细和 Drawable
一致,即第一次丈量的宽度是 Drawable
的实践宽度。
那高度怎么不是 Drawable
的高度呢?因为 RelativeLayout
第一次丈量只是确定了 ImageView
的宽度,第2次又根据 ImageView
的实践高度进行丈量,因而便出现了上图的状况,即 adjustViewBounds
失效了。
已然 RelativeLayout
是先丈量宽度,那我把宽度固定,是不是就没问题了,没错,咱们修改代码测验一下
到这儿,咱们基本理清了 RelativeLayout
的丈量方法对 ImageView
的 adjustViewBounds
属性的影响,最后咱们回到事务上,为什么只要新上的表情(经过接口获取)显现偏小,而内置图片确能正常显现呢?
原因是内置图片的尺度放在对应 dpi 目录下,会根据设备 dpi 进行缩放,因而即便 adjustViewBounds
失效,也能拉伸到对应尺度,因而显现正常,而经过接口下载的图片,density
默许和设备一致,因而在 density
比较高的设备上,无法主动拉伸到预期的尺度。
处理
弄清楚了问题的原因就很容易处理了,这儿 Emoji 容器中只要一个 ImageView
保持居中,不依赖 RelativeLayout
的特性,因而直接替换为 FrameLayout
即可。
总结
本文主要经过一个事务 bug,经过源码解读,发现 ImageView
与 RelativeLayout
组合运用,在特定场景下 adjustViewBounds
属性会“失效”的问题,终究经过替换为 FrameLayout
来处理。
不清楚这个问题是 Google 是有意为之,还是一个 Bug,现在官方文档上暂时未发现有相关阐明,有了解的大佬能够帮小弟解解惑。