使用GridLayoutManager(3列)的RecyclerView中居中ImageView尺寸异常问题
解决3列GridLayoutManager中ImageView尺寸不一致问题
问题根源
GridLayoutManager默认列宽分配逻辑下,若屏幕宽度无法被列数整除,剩余像素会被分配给部分列,导致列宽存在微小差异,进而ImageView的宽高随之变化(从日志看中间列多分配了5像素宽度,高度按比例增加10像素)。ScaleType无法解决View本身尺寸不一致的问题,需从列宽统一和布局约束入手。
解决方案
1. 强制每列宽度完全一致
通过计算精确列宽,让RecyclerView的每个Item宽度统一:
首先在初始化RecyclerView时计算列宽:
private fun initRecycler(){ val gridLayoutManager = GridLayoutManager(context,3) // 计算屏幕可用宽度,减去RecyclerView的左右内边距 val screenWidth = context.resources.displayMetrics.widthPixels val rvPadding = binding.rvWallpapers.paddingLeft + binding.rvWallpapers.paddingRight val columnWidth = (screenWidth - rvPadding) / 3 binding.rvWallpapers.layoutManager = gridLayoutManager mainAdapter = MainAdapter(context, this, columnWidth) // 将列宽传入Adapter binding.rvWallpapers.addOnScrolledToEnd { binding.skvLoadingEnd.isVisible = true initCategory() } binding.rvWallpapers.adapter = mainAdapter }
然后在Adapter的onBindViewHolder中给Item设置固定宽度:
class MainAdapter( private val context: Context, private val listener: OnItemClickListener, private val columnWidth: Int ) : RecyclerView.Adapter<MainAdapter.ViewHolder>() { // ... 其他代码 override fun onBindViewHolder(holder: ViewHolder, position: Int) { // 设置Item根布局的固定宽度 val layoutParams = holder.itemView.layoutParams as RecyclerView.LayoutParams layoutParams.width = columnWidth holder.itemView.layoutParams = layoutParams // 加载图片逻辑 Glide.with(context) .load(sizesModel.url) .centerCrop() .listener(object : RequestListener<Drawable?> { override fun onLoadFailed( e: GlideException?, model: Any?, target: Target<Drawable?>?, isFirstResource: Boolean ): Boolean { return false } override fun onResourceReady( resource: Drawable?, model: Any?, target: Target<Drawable?>?, dataSource: DataSource?, isFirstResource: Boolean ): Boolean { Log.d("sizes", "width: "+holder.binding.ivWallpapers.width+" height: "+holder.binding.ivWallpapers.height) holder.binding.skvLoading.isVisible = false return false } }) .into(holder.binding.ivWallpapers) } }
2. 用ConstraintLayout固定ImageView宽高比
在Item布局文件中,通过ConstraintLayout给ImageView设置固定宽高比,确保即使列宽有微小差异,图片比例也保持一致(建议配合方案1使用):
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/ivWallpapers" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintDimensionRatio="1:2" <!-- 对应日志中宽高1:2的比例 --> android:scaleType="centerCrop" android:adjustViewBounds="true"/> </androidx.constraintlayout.widget.ConstraintLayout>
3. 检查布局中的padding/margin
确认Item布局文件中,是否存在中间列Item额外的padding或margin设置,这也会导致ImageView尺寸不一致,需保证所有Item的内外边距完全相同。
内容的提问来源于stack exchange,提问作者sheisde
相关产品推荐
相关产品推荐

