RecyclerView中图片无法显示完整高度,不使用第三方库如何解决?
问题根因
图片无法显示完整高度的核心原因有两点:
- RecyclerView首次测量列表项尺寸时,会基于本地占位图的尺寸完成布局计算,异步加载完远程图片后,ImageView没有主动触发重新测量调整自身尺寸,导致真实图片被原有控件边界裁剪。
- 现有加载逻辑没有适配控件尺寸计算最优Bitmap加载参数,也没有处理列表复用带来的图片错位问题。
解决方案(全程无第三方依赖)
1. 修改列表项ImageView布局属性
将ImageView的高度改为wrap_content,同时开启adjustViewBounds属性,让ImageView可以根据加载的图片宽高比自动调整自身尺寸:
<androidx.appcompat.widget.AppCompatImageView android:id="@+id/iv_song_image" android:layout_width="match_parent" android:layout_height="wrap_content" android:adjustViewBounds="true" android:scaleType="fitCenter" app:imageUrl="@{songObject.songImage}" android:src="@drawable/img_song_cover" />
如果你的RecyclerView是横向滚动、高度固定为200dp,可将scaleType改为centerInside,保证图片完整显示在控件范围内。
2. 优化图片加载逻辑
增加复用校验、Bitmap采样率压缩、加载完成后主动触发重新测量:
@BindingAdapter("imageUrl") fun ImageView.bindImage(imgUrl: String?) { // 设置tag避免列表复用导致图片错位 tag = imgUrl imgUrl?.let { url -> val imgUri = url.toUri().buildUpon().scheme("https").build().toString() // 获取当前控件宽度用于计算采样率 val targetWidth = measuredWidth.takeIf { it > 0 } ?: resources.displayMetrics.widthPixels / 3 thread(start = true) { val bitmap = decodeSampledBitmapFromUrl(imgUri, targetWidth) // 回到主线程校验tag一致再设置图片 post { if (tag == imgUrl && bitmap != null) { setImageBitmap(bitmap) // 触发重新测量,调整控件高度适配图片 requestLayout() } } } } } private fun decodeSampledBitmapFromUrl(imageUrl: String, targetWidth: Int): Bitmap? { return try { // 第一次仅解码图片边界获取原始宽高 val conn = URL(imageUrl).openConnection() conn.connect() val inputStream = conn.getInputStream() val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } BitmapFactory.decodeStream(inputStream, null, options) inputStream.close() // 计算最优采样率降低内存占用 options.inSampleSize = calculateInSampleSize(options, targetWidth) options.inJustDecodeBounds = false // 按采样率加载真实Bitmap val newConn = URL(imageUrl).openConnection() newConn.connect() val newInputStream = newConn.getInputStream() val bitmap = BitmapFactory.decodeStream(newInputStream, null, options) newInputStream.close() bitmap } catch (e: Exception) { Log.e(ContentValues.TAG, "加载图片异常: $e") null } } private fun calculateInSampleSize(options: BitmapFactory.Options, targetWidth: Int): Int { val rawWidth = options.outWidth var inSampleSize = 1 if (rawWidth > targetWidth) { val halfWidth = rawWidth / 2 while (halfWidth / inSampleSize >= targetWidth) { inSampleSize *= 2 } } return inSampleSize }
3. 可选性能优化
可以自行实现LruCache内存缓存,存储已经加载过的Bitmap,避免滚动列表时重复下载相同图片,进一步提升加载流畅度。
内容的提问来源于stack exchange,提问作者Ahmed Mamdouh
相关产品推荐
相关产品推荐

