如何使用GridLayoutManager与RecyclerView设置列间距? 在我的布局中设置空白/填充没有效果。
当前回答
这个问题的答案似乎比他们应该做的要复杂。以下是我的看法。
假设您希望网格项之间有1dp的间距。做以下几点:
为每个项目添加0.5dp的填充 给RecycleView添加-0.5dp的填充 就是这样!:)
其他回答
下面的代码工作得很好,每个列都有相同的宽度:
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
private boolean includeEdge;
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item position
int column = position % spanCount; // item column
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)
if (position < spanCount) { // top edge
outRect.top = spacing;
}
outRect.bottom = spacing; // item bottom
} else {
outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
if (position >= spanCount) {
outRect.top = spacing; // item top
}
}
}
}
使用
1. 没有优势
int spanCount = 3; // 3 columns
int spacing = 50; // 50px
boolean includeEdge = false;
recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing, includeEdge));
2. 与边缘
int spanCount = 3; // 3 columns
int spacing = 50; // 50px
boolean includeEdge = true;
recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing, includeEdge));
如果你有一个在列表和网格之间切换的拨动开关,不要忘记在设置任何新的项目装饰之前调用recyclerView.removeItemDecoration(..)。如果不是这样,那么新的间隔计算将是不正确的。
就像这样:
recyclerView.removeItemDecoration(gridItemDecorator)
recyclerView.removeItemDecoration(listItemDecorator)
if (showAsList) {
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
recyclerView.addItemDecoration(listItemDecorator)
} else {
recyclerView.layoutManager = GridLayoutManager(this, spanCount)
recyclerView.addItemDecoration(gridItemDecorator)
}
只有一个简单的解决方案,您可以记住并在任何需要的地方实施。没有bug,没有疯狂的计算。在卡片/物品布局中放置空白,并在RecyclerView中放置相同大小的填充:
item_layout.xml
<CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:margin="10dp">
activity_layout.xml
<RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"/>
更新:
选择的答案几乎是完美的,但根据空间的不同,项目的宽度可能不相等。(对我来说,这很关键)。所以我最终用这个代码增加了一点空间,所以项目都是相同的宽度。
class GridSpacingItemDecoration(private val columnCount: Int, @Px preferredSpace: Int, private val includeEdge: Boolean): RecyclerView.ItemDecoration() {
/**
* In this algorithm space should divide by 3 without remnant or width of items can have a difference
* and we want them to be exactly the same
*/
private val space = if (preferredSpace % 3 == 0) preferredSpace else (preferredSpace + (3 - preferredSpace % 3))
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) {
val position = parent.getChildAdapterPosition(view)
if (includeEdge) {
when {
position % columnCount == 0 -> {
outRect.left = space
outRect.right = space / 3
}
position % columnCount == columnCount - 1 -> {
outRect.right = space
outRect.left = space / 3
}
else -> {
outRect.left = space * 2 / 3
outRect.right = space * 2 / 3
}
}
if (position < columnCount) {
outRect.top = space
}
outRect.bottom = space
} else {
when {
position % columnCount == 0 -> outRect.right = space * 2 / 3
position % columnCount == columnCount - 1 -> outRect.left = space * 2 / 3
else -> {
outRect.left = space / 3
outRect.right = space / 3
}
}
if (position >= columnCount) {
outRect.top = space
}
}
}
}
class VerticalGridSpacingDecoration(private val spacing: Int) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: State
) {
val layoutManager = parent.layoutManager as? GridLayoutManager
if (layoutManager == null || layoutManager.orientation != VERTICAL) {
return super.getItemOffsets(outRect, view, parent, state)
}
val spanCount = layoutManager.spanCount
val position = parent.getChildAdapterPosition(view)
val column = position % spanCount
with(outRect) {
left = if (column == 0) 0 else spacing / 2
right = if (column == spanCount.dec()) 0 else spacing / 2
top = if (position < spanCount) 0 else spacing
}
}
}
推荐文章
- 警告:API ' variable . getjavacompile()'已过时,已被' variable . getjavacompileprovider()'取代
- 安装APK时出现错误
- 碎片中的onCreateOptionsMenu
- TextView粗体通过XML文件?
- 如何使线性布局的孩子之间的空间?
- DSL元素android.dataBinding。enabled'已过时,已被'android.buildFeatures.dataBinding'取代
- ConstraintLayout:以编程方式更改约束
- PANIC: AVD系统路径损坏。检查ANDROID_SDK_ROOT值
- 如何生成字符串类型的buildConfigField
- Recyclerview不调用onCreateViewHolder
- Android API 21工具栏填充
- Android L中不支持操作栏导航模式
- 如何在TextView中添加一个子弹符号?
- PreferenceManager getDefaultSharedPreferences在Android Q中已弃用
- 在Android Studio中创建aar文件