RecyclerView网格单元格自动适配屏幕宽度问题求助
解决RecyclerView实现正方形网格的方案
方案一:纯XML布局实现(最省心)
先修改你的item布局,原来的CardView直接放在DataBinding根标签下,导致比例约束失效,得加个ConstraintLayout当容器:
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintDimensionRatio="1:1" android:clickable="true" app:cardUseCompatPadding="false" app:cardPreventCornerOverlap="false"> <TextView android:id="@+id/itemElevation" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textColor="@android:color/black" app:elevationItem="@{item}" tools:text="33" tools:background="@android:color/holo_orange_dark"/> </androidx.cardview.widget.CardView> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
- 加ConstraintLayout是为了让
layout_constraintDimensionRatio生效,CardView高度设为0dp,靠比例自动和宽度一致,实现正方形 - 删掉TextView的固定宽高,改成
match_parent,让它填满CardView - 开启
cardUseCompatPadding和cardPreventCornerOverlap是为了去掉CardView自带的多余空隙,确保单元格无缝衔接
RecyclerView的XML不用大改,只要保证它是match_parent宽高,spanCount可以随便改,改完单元格会自动适配宽度并保持正方形。
方案二:代码动态算尺寸
不想改布局结构的话,直接在Adapter里动态设置item高度:
第一步:修改item布局
把CardView宽度设为match_parent,TextView改成填满父容器:
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true"> <TextView android:id="@+id/itemElevation" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textColor="@android:color/black" app:elevationItem="@{item}" tools:text="33" tools:background="@android:color/holo_orange_dark"/> </androidx.cardview.widget.CardView> </layout>
第二步:在Adapter里设置高度
在onCreateViewHolder里算出每个item的宽度(RecyclerView宽度除以列数),再把高度设成和宽度一样:
class YourAdapter(private val spanCount: Int) : RecyclerView.Adapter<YourAdapter.ViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val inflater = LayoutInflater.from(parent.context) val binding = ItemCellBinding.inflate(inflater, parent, false) // 计算每个item的宽度,直接用父容器宽度除以列数 val itemWidth = parent.width / spanCount // 强制高度等于宽度,实现正方形 binding.root.layoutParams.height = itemWidth return ViewHolder(binding) } // 其他必要方法... }
如果RecyclerView初始化时还没测好宽度,parent.width可能为0,那就加个监听,等布局完成后再刷新:
gridView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { gridView.viewTreeObserver.removeOnGlobalLayoutListener(this) // 刷新Adapter让尺寸生效 adapter.notifyDataSetChanged() } })
重点提醒
- 绝对不能给单元格里的控件设固定宽高,不然肯定会有空隙或者适配不了列数变化
- CardView自带的padding容易被忽略,要关掉那些默认的padding属性
内容的提问来源于stack exchange,提问作者Seb
相关产品推荐
相关产品推荐

