如何使用GridLayoutManager与RecyclerView设置列间距? 在我的布局中设置空白/填充没有效果。
当前回答
为了使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;
}
其他回答
为了使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;
}
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) {
StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
int column = params.getSpanIndex();
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
}
}
}
}
与edwardaa的回答略有不同,不同之处在于列是如何确定的,因为在一些情况下,例如具有不同高度的项目,列不能简单地通过% spanCount确定
下面的代码工作得很好,每个列都有相同的宽度:
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));
这是我在Kotlin中编写的更灵活的版本,您可以在dp中设置参数。
class ItemDividerGrid(private val numberOfColumns: Int, private val rowSpacingDP: Float = 0f, private val columnSpacingDP: Float = 0f, private val edgeSpacingVerticalDP: Float = 0f, private val edgeSpacingHorizontalDP: Float = 0f) : ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val position = parent.getChildAdapterPosition(view)
val numberOfRows = (parent.adapter?.itemCount?:-1)/numberOfColumns
val column = position % numberOfColumns
val row = position / numberOfColumns
val context = view.context
///horizontal
when(column){
0 -> {
outRect.left = convertDpToPixel(edgeSpacingVerticalDP,context)
outRect.right = convertDpToPixel(columnSpacingDP/2, context)
}
numberOfColumns-1 -> {
outRect.left = convertDpToPixel(columnSpacingDP/2, context)
outRect.right = convertDpToPixel(edgeSpacingVerticalDP, context)
}
else -> {
outRect.left = convertDpToPixel(columnSpacingDP/2, context)
outRect.right = convertDpToPixel(columnSpacingDP/2, context)
}
}
//vertical
when(row){
0 -> {
outRect.top = convertDpToPixel(edgeSpacingHorizontalDP,context)
outRect.bottom = convertDpToPixel(rowSpacingDP/2, context)
}
numberOfRows -> {
outRect.top = convertDpToPixel(rowSpacingDP/2, context)
outRect.bottom = convertDpToPixel(edgeSpacingHorizontalDP, context)
}
else -> {
outRect.top = convertDpToPixel(rowSpacingDP/2, context)
outRect.bottom = convertDpToPixel(rowSpacingDP/2, context)
}
}
}
fun convertDpToPixel(dp: Float, context: Context?): Int {
return if (context != null) {
val resources = context.resources
val metrics = resources.displayMetrics
(dp * (metrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)).roundToInt()
} else {
val metrics = Resources.getSystem().displayMetrics
(dp * (metrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)).roundToInt()
}
}
}
确保你在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));
推荐文章
- Android选择器和文本颜色
- 视图绑定-我如何获得包含布局的绑定?
- 在Android Studio中改变矢量资产的填充颜色
- 在构建中编写注释的语法是什么?gradle文件?
- 如何以编程方式添加按钮色调
- 用Android Studio进行调试永远停留在“等待调试器”状态
- Openssl不被视为内部或外部命令
- 无法执行dex:在Eclipse中超过GC开销限制
- 如何以编程方式将视图添加到视图
- 单击url会打开默认浏览器
- 使用Retrofit刷新OAuth令牌,而不修改所有调用
- 多个dex文件定义了landoid /support/v4/accessibilityservice/AccessibilityServiceInfoCompat
- 如何获得动作栏的高度?
- 从活动外部调用startActivity() ?
- createScaledBitmap的过滤器参数做什么?