如何使用GridLayoutManager与RecyclerView设置列间距? 在我的布局中设置空白/填充没有效果。
当前回答
试试这个。它会照顾到周围的等距。适用于列表,网格和StaggeredGrid。
编辑
更新后的代码应该可以处理大多数带有跨度、方向等的角落情况。 注意,如果在GridLayoutManager中使用setSpanSizeLookup(),出于性能考虑,建议设置setSpanIndexCacheEnabled()。
注意,似乎与StaggeredGrid,似乎有一个错误的索引的孩子变得古怪和难以跟踪,所以下面的代码可能不会很好地与StaggeredGridLayoutManager。
public class ListSpacingDecoration extends RecyclerView.ItemDecoration {
private static final int VERTICAL = OrientationHelper.VERTICAL;
private int orientation = -1;
private int spanCount = -1;
private int spacing;
private int halfSpacing;
public ListSpacingDecoration(Context context, @DimenRes int spacingDimen) {
spacing = context.getResources().getDimensionPixelSize(spacingDimen);
halfSpacing = spacing / 2;
}
public ListSpacingDecoration(int spacingPx) {
spacing = spacingPx;
halfSpacing = spacing / 2;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (orientation == -1) {
orientation = getOrientation(parent);
}
if (spanCount == -1) {
spanCount = getTotalSpan(parent);
}
int childCount = parent.getLayoutManager().getItemCount();
int childIndex = parent.getChildAdapterPosition(view);
int itemSpanSize = getItemSpanSize(parent, childIndex);
int spanIndex = getItemSpanIndex(parent, childIndex);
/* INVALID SPAN */
if (spanCount < 1) return;
setSpacings(outRect, parent, childCount, childIndex, itemSpanSize, spanIndex);
}
protected void setSpacings(Rect outRect, RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
outRect.top = halfSpacing;
outRect.bottom = halfSpacing;
outRect.left = halfSpacing;
outRect.right = halfSpacing;
if (isTopEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
outRect.top = spacing;
}
if (isLeftEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
outRect.left = spacing;
}
if (isRightEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
outRect.right = spacing;
}
if (isBottomEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
outRect.bottom = spacing;
}
}
@SuppressWarnings("all")
protected int getTotalSpan(RecyclerView parent) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getSpanCount();
} else if (mgr instanceof StaggeredGridLayoutManager) {
return ((StaggeredGridLayoutManager) mgr).getSpanCount();
} else if (mgr instanceof LinearLayoutManager) {
return 1;
}
return -1;
}
@SuppressWarnings("all")
protected int getItemSpanSize(RecyclerView parent, int childIndex) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanSize(childIndex);
} else if (mgr instanceof StaggeredGridLayoutManager) {
return 1;
} else if (mgr instanceof LinearLayoutManager) {
return 1;
}
return -1;
}
@SuppressWarnings("all")
protected int getItemSpanIndex(RecyclerView parent, int childIndex) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanIndex(childIndex, spanCount);
} else if (mgr instanceof StaggeredGridLayoutManager) {
return childIndex % spanCount;
} else if (mgr instanceof LinearLayoutManager) {
return 0;
}
return -1;
}
@SuppressWarnings("all")
protected int getOrientation(RecyclerView parent) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof LinearLayoutManager) {
return ((LinearLayoutManager) mgr).getOrientation();
} else if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getOrientation();
} else if (mgr instanceof StaggeredGridLayoutManager) {
return ((StaggeredGridLayoutManager) mgr).getOrientation();
}
return VERTICAL;
}
protected boolean isLeftEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return spanIndex == 0;
} else {
return (childIndex == 0) || isFirstItemEdgeValid((childIndex < spanCount), parent, childIndex);
}
}
protected boolean isRightEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return (spanIndex + itemSpanSize) == spanCount;
} else {
return isLastItemEdgeValid((childIndex >= childCount - spanCount), parent, childCount, childIndex, spanIndex);
}
}
protected boolean isTopEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return (childIndex == 0) || isFirstItemEdgeValid((childIndex < spanCount), parent, childIndex);
} else {
return spanIndex == 0;
}
}
protected boolean isBottomEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return isLastItemEdgeValid((childIndex >= childCount - spanCount), parent, childCount, childIndex, spanIndex);
} else {
return (spanIndex + itemSpanSize) == spanCount;
}
}
protected boolean isFirstItemEdgeValid(boolean isOneOfFirstItems, RecyclerView parent, int childIndex) {
int totalSpanArea = 0;
if (isOneOfFirstItems) {
for (int i = childIndex; i >= 0; i--) {
totalSpanArea = totalSpanArea + getItemSpanSize(parent, i);
}
}
return isOneOfFirstItems && totalSpanArea <= spanCount;
}
protected boolean isLastItemEdgeValid(boolean isOneOfLastItems, RecyclerView parent, int childCount, int childIndex, int spanIndex) {
int totalSpanRemaining = 0;
if (isOneOfLastItems) {
for (int i = childIndex; i < childCount; i++) {
totalSpanRemaining = totalSpanRemaining + getItemSpanSize(parent, i);
}
}
return isOneOfLastItems && (totalSpanRemaining <= spanCount - spanIndex);
}
}
希望能有所帮助。
其他回答
为了使https://stackoverflow.com/a/29905000/1649371(上面)解决方案工作,我必须修改以下方法(以及所有后续调用)
@SuppressWarnings("all")
protected int getItemSpanSize(RecyclerView parent, View view, int childIndex) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanSize(childIndex);
} else if (mgr instanceof StaggeredGridLayoutManager) {
return ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).isFullSpan() ? spanCount : 1;
} else if (mgr instanceof LinearLayoutManager) {
return 1;
}
return -1;
}
@SuppressWarnings("all")
protected int getItemSpanIndex(RecyclerView parent, View view, int childIndex) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanIndex(childIndex, spanCount);
} else if (mgr instanceof StaggeredGridLayoutManager) {
return ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
} else if (mgr instanceof LinearLayoutManager) {
return 0;
}
return -1;
}
上面的回答已经阐明了设置边缘处理GridLayoutManager和LinearLayoutManager的方法。
但是对于StaggeredGridLayoutManager, Pirdad Sakhizada的回答是:“它可能不太适合StaggeredGridLayoutManager”。应该是关于IndexOfSpan的问题。
您可以通过以下方式获取:
private static class MyItemDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
int index = ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
}
}
试试这个。它会照顾到周围的等距。适用于列表,网格和StaggeredGrid。
编辑
更新后的代码应该可以处理大多数带有跨度、方向等的角落情况。 注意,如果在GridLayoutManager中使用setSpanSizeLookup(),出于性能考虑,建议设置setSpanIndexCacheEnabled()。
注意,似乎与StaggeredGrid,似乎有一个错误的索引的孩子变得古怪和难以跟踪,所以下面的代码可能不会很好地与StaggeredGridLayoutManager。
public class ListSpacingDecoration extends RecyclerView.ItemDecoration {
private static final int VERTICAL = OrientationHelper.VERTICAL;
private int orientation = -1;
private int spanCount = -1;
private int spacing;
private int halfSpacing;
public ListSpacingDecoration(Context context, @DimenRes int spacingDimen) {
spacing = context.getResources().getDimensionPixelSize(spacingDimen);
halfSpacing = spacing / 2;
}
public ListSpacingDecoration(int spacingPx) {
spacing = spacingPx;
halfSpacing = spacing / 2;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (orientation == -1) {
orientation = getOrientation(parent);
}
if (spanCount == -1) {
spanCount = getTotalSpan(parent);
}
int childCount = parent.getLayoutManager().getItemCount();
int childIndex = parent.getChildAdapterPosition(view);
int itemSpanSize = getItemSpanSize(parent, childIndex);
int spanIndex = getItemSpanIndex(parent, childIndex);
/* INVALID SPAN */
if (spanCount < 1) return;
setSpacings(outRect, parent, childCount, childIndex, itemSpanSize, spanIndex);
}
protected void setSpacings(Rect outRect, RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
outRect.top = halfSpacing;
outRect.bottom = halfSpacing;
outRect.left = halfSpacing;
outRect.right = halfSpacing;
if (isTopEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
outRect.top = spacing;
}
if (isLeftEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
outRect.left = spacing;
}
if (isRightEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
outRect.right = spacing;
}
if (isBottomEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
outRect.bottom = spacing;
}
}
@SuppressWarnings("all")
protected int getTotalSpan(RecyclerView parent) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getSpanCount();
} else if (mgr instanceof StaggeredGridLayoutManager) {
return ((StaggeredGridLayoutManager) mgr).getSpanCount();
} else if (mgr instanceof LinearLayoutManager) {
return 1;
}
return -1;
}
@SuppressWarnings("all")
protected int getItemSpanSize(RecyclerView parent, int childIndex) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanSize(childIndex);
} else if (mgr instanceof StaggeredGridLayoutManager) {
return 1;
} else if (mgr instanceof LinearLayoutManager) {
return 1;
}
return -1;
}
@SuppressWarnings("all")
protected int getItemSpanIndex(RecyclerView parent, int childIndex) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanIndex(childIndex, spanCount);
} else if (mgr instanceof StaggeredGridLayoutManager) {
return childIndex % spanCount;
} else if (mgr instanceof LinearLayoutManager) {
return 0;
}
return -1;
}
@SuppressWarnings("all")
protected int getOrientation(RecyclerView parent) {
RecyclerView.LayoutManager mgr = parent.getLayoutManager();
if (mgr instanceof LinearLayoutManager) {
return ((LinearLayoutManager) mgr).getOrientation();
} else if (mgr instanceof GridLayoutManager) {
return ((GridLayoutManager) mgr).getOrientation();
} else if (mgr instanceof StaggeredGridLayoutManager) {
return ((StaggeredGridLayoutManager) mgr).getOrientation();
}
return VERTICAL;
}
protected boolean isLeftEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return spanIndex == 0;
} else {
return (childIndex == 0) || isFirstItemEdgeValid((childIndex < spanCount), parent, childIndex);
}
}
protected boolean isRightEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return (spanIndex + itemSpanSize) == spanCount;
} else {
return isLastItemEdgeValid((childIndex >= childCount - spanCount), parent, childCount, childIndex, spanIndex);
}
}
protected boolean isTopEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return (childIndex == 0) || isFirstItemEdgeValid((childIndex < spanCount), parent, childIndex);
} else {
return spanIndex == 0;
}
}
protected boolean isBottomEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {
if (orientation == VERTICAL) {
return isLastItemEdgeValid((childIndex >= childCount - spanCount), parent, childCount, childIndex, spanIndex);
} else {
return (spanIndex + itemSpanSize) == spanCount;
}
}
protected boolean isFirstItemEdgeValid(boolean isOneOfFirstItems, RecyclerView parent, int childIndex) {
int totalSpanArea = 0;
if (isOneOfFirstItems) {
for (int i = childIndex; i >= 0; i--) {
totalSpanArea = totalSpanArea + getItemSpanSize(parent, i);
}
}
return isOneOfFirstItems && totalSpanArea <= spanCount;
}
protected boolean isLastItemEdgeValid(boolean isOneOfLastItems, RecyclerView parent, int childCount, int childIndex, int spanIndex) {
int totalSpanRemaining = 0;
if (isOneOfLastItems) {
for (int i = childIndex; i < childCount; i++) {
totalSpanRemaining = totalSpanRemaining + getItemSpanSize(parent, i);
}
}
return isOneOfLastItems && (totalSpanRemaining <= spanCount - spanIndex);
}
}
希望能有所帮助。
如果你有一个在列表和网格之间切换的拨动开关,不要忘记在设置任何新的项目装饰之前调用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)
}
确保你在gradle模块中实现了这个:
implementation 'com.github.grzegorzojdana:SpacingItemDecoration:1.1.0'
创建这个简单的函数:
public static int dpToPx(Context c, int dp) {
Resources r = c.getResources();
return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()));
}
最后实现如下所示的空格:
photosRecycler.addItemDecoration(new SpacingItemDecoration(2, dpToPx(this, 4), true));
推荐文章
- 警告: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文件