Android ImageView显示全屏图片如何保持长宽比且不裁剪不拉伸
实现前提说明
在图片长宽比与设备屏幕长宽比不一致的前提下,「不裁剪、保持原有长宽比、完全铺满屏幕无留白」三个条件无法同时满足,你的需求为前两项,因此比例不一致时必然会出现留白区域,可通过设置ImageView背景色统一视觉效果。
方案1:原生控件实现(无需自定义)
直接使用系统自带ImageView即可满足需求,XML配置如下:
<ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitCenter" android:background="@android:color/black" />
参数说明:
fitCenter:系统自带的缩放模式,会按照图片原始长宽比缩放,直到图片的宽高都小于等于ImageView的宽高,最终居中显示,完全不会裁剪图片,也不会产生拉伸变形- 宽高设为
match_parent实现全屏效果,背景可根据需求替换为对应颜色或Drawable
之前方案失效的原因
- 自定义
ScaleImageView逻辑缺陷:当ImageView宽高都设为match_parent时,onMeasure中拿到的measuredWidth和measuredHeight都不为0,直接走了else分支返回原始测量值,自定义比例逻辑完全没有生效,搭配fitXY的缩放模式自然会出现拉伸 - 之前的XML配置用了
centerCrop缩放模式,该模式本身的规则就是裁剪图片超出控件的部分,无论是否加adjustViewBounds都会产生裁剪效果;且adjustViewBounds仅在宽高其中一项为wrap_content时生效,两项都为match_parent时该属性无效。
方案2:自定义控件实现
如果需要保留自定义ImageView的扩展能力,修改代码如下即可:
class ScaleImageView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyle: Int = 0 ) : AppCompatImageView(context, attrs, defStyle) { init { // 固定缩放模式,避免外部设置错误 scaleType = ScaleType.FIT_CENTER } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val drawable = drawable ?: run { super.onMeasure(widthMeasureSpec, heightMeasureSpec) return } // 获取控件可用宽高 val viewWidth = MeasureSpec.getSize(widthMeasureSpec) val viewHeight = MeasureSpec.getSize(heightMeasureSpec) // 计算图片和控件的长宽比 val drawableRatio = drawable.intrinsicWidth.toFloat() / drawable.intrinsicHeight.toFloat() val viewRatio = viewWidth.toFloat() / viewHeight.toFloat() val finalWidth: Int val finalHeight: Int if (drawableRatio > viewRatio) { // 图片宽高比大于控件,宽度撑满,高度按比例计算 finalWidth = viewWidth finalHeight = (viewWidth / drawableRatio).toInt() } else { // 图片宽高比小于等于控件,高度撑满,宽度按比例计算 finalHeight = viewHeight finalWidth = (viewHeight * drawableRatio).toInt() } setMeasuredDimension(finalWidth, finalHeight) } }
使用时直接将该控件的宽高设为match_parent即可,无需额外设置scaleType。
注意事项
- 若使用Glide、Coil等第三方图片加载框架,不要给加载请求设置
centerCrop、fitXY等变换参数,避免覆盖ImageView本身的缩放规则 - 网络图片加载完成后需要触发重新测量,可在图片加载成功的回调中调用
requestLayout()更新布局
内容的提问来源于stack exchange,提问作者testivanivan
相关产品推荐
相关产品推荐

