自定义RecyclerView的ItemDecoration,用于处理网格布局的间距,网格布局间距装饰器(支持边缘间距独立控制),为RecyclerView网格布局提供灵活的间距控制,可单独设置各边缘间距。
核心功能说明:
- 灵活的边缘控制:可单独设置首列/末列/首行/末行的间距
- 智能间距分配:
- 多列布局时自动将间距平分到相邻item两侧
- 单列布局时直接应用指定间距
3.两种边缘模式:
- includeEdge=true:默认包含顶部/底部边缘间距
- includeEdge=false:不包含默认边缘间距(可单独设置)
4.辅助计算功能:提供getTotalWidthNeeded()方法预计算item宽度

如:GridLayoutManager 设计一个一行4列的,且每列的间距都是10dp
// 在Activity或Fragment中
RecyclerView recyclerView = findViewById(R.id.recyclerView);
// 设置GridLayoutManager,4列
GridLayoutManager layoutManager = new GridLayoutManager(this, 4);
recyclerView.setLayoutManager(layoutManager);
// 设置ItemDecoration来添加间距
int spacingInPixels = getResources().getDimensionPixelSize(R.dimen.grid_spacing);
// 移除旧的 ItemDecoration(避免重复添加)
if (recyclerView.getItemDecorationCount() > 0) {
recyclerView.removeItemDecorationAt(0);
}
// 添加自定义边距
recyclerView.addItemDecoration(new GridSpacingItemDecoration(4,
spacingInPixels ,
true,
spacingInPixels,
spacingInPixels,
0,
spacingInPixels));
// 设置适配器
ImageAdapter adapter = new ImageAdapter(imageList); // 假设有适配器
recyclerView.setAdapter(adapter);
GridSpacingItemDecoration.java 代码:
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* 网格布局间距装饰器(支持边缘间距独立控制)
* 功能:为RecyclerView网格布局提供灵活的间距控制,可单独设置各边缘间距
*/
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private final int spanCount; // 网格列数
private final int spacing; // 默认间距大小(像素)
private final boolean includeEdge; // 是否包含边缘间距(影响顶部/底部默认行为)
// 以下参数为可选边缘间距控制(-1表示使用默认间距)
private int includeFirstColumnSpacing = -1; // 第一列左边距(可覆盖默认值)
private int includeLastColumnSpacing = -1; // 最后一列右边距(可覆盖默认值)
private int includeFirstRowTopSpacing = -1; // 第一行上边距(可覆盖默认值)
private int includeLastRowBottomSpacing = -1; // 最后一行下边距(可覆盖默认值)
/**
* 全参数构造函数
*
* @param spanCount 网格列数(必须大于0)
* @param spacing 默认间距值(像素)
* @param includeEdge 是否包含边缘间距(影响顶部/底部默认行为)
* @param includeFirstColumnSpacing 第一列左边距(-1表示使用默认间距)
* @param includeLastColumnSpacing 最后一列右边距(-1表示使用默认间距)
* @param includeFirstRowTopSpacing 第一行上边距(-1表示使用默认间距)
* @param includeLastRowBottomSpacing 最后一行下边距(-1表示使用默认间距)
*/
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge,
int includeFirstColumnSpacing,
int includeLastColumnSpacing,
int includeFirstRowTopSpacing,
int includeLastRowBottomSpacing) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
this.includeFirstColumnSpacing = includeFirstColumnSpacing;
this.includeLastColumnSpacing = includeLastColumnSpacing;
this.includeFirstRowTopSpacing = includeFirstRowTopSpacing;
this.includeLastRowBottomSpacing = includeLastRowBottomSpacing;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // 当前item位置
int column = position % spanCount; // 当前item所在列(0~spanCount-1)
int totalItemCount = parent.getAdapter().getItemCount(); // 总item数
int totalRows = (int) Math.ceil((double) totalItemCount / spanCount); // 计算总行数
int currentRow = position / spanCount + 1; // 当前行号(从1开始)
/* ========== 1. 处理左右边距 ========== */
if (spanCount == 1) {
// 单列特殊情况处理
outRect.left = getEffectiveSpacing(includeFirstColumnSpacing, spacing);
outRect.right = getEffectiveSpacing(includeLastColumnSpacing, spacing);
} else {
// 多列常规处理
if (column == 0) {
// 第一列:左间距可定制,右间距为默认一半
outRect.left = getEffectiveSpacing(includeFirstColumnSpacing, spacing);
outRect.right = spacing / 2;
} else if (column == spanCount - 1) {
// 最后一列:左间距为默认一半,右间距可定制
outRect.left = spacing / 2;
outRect.right = getEffectiveSpacing(includeLastColumnSpacing, spacing);
} else {
// 中间列:左右间距均为默认一半(实现等间距分布)
outRect.left = spacing / 2;
outRect.right = spacing / 2;
}
}
/* ========== 2. 处理上下边距 ========== */
if (includeEdge) {
// 包含边缘模式
if (currentRow == 1) {
// 第一行顶部间距
outRect.top = getEffectiveSpacing(includeFirstRowTopSpacing, spacing);
}
// 底部间距处理
if (currentRow == totalRows) {
// 最后一行底部间距可定制
outRect.bottom = getEffectiveSpacing(includeLastRowBottomSpacing, spacing);
} else if (currentRow < totalRows) {
// 中间行固定底部间距
outRect.bottom = spacing;
}
} else {
// 不包含边缘模式
outRect.top = currentRow == 1 ?
getEffectiveSpacing(includeFirstRowTopSpacing, spacing) : spacing;
// 最后一行特殊处理
if (currentRow == totalRows) {
outRect.bottom = getEffectiveSpacing(includeLastRowBottomSpacing, spacing);
}
}
}
/**
* 获取有效间距值
* @param customSpacing 自定义间距值(-1表示使用默认值)
* @param defaultSpacing 默认间距值
* @return 实际使用的间距值
*/
private int getEffectiveSpacing(int customSpacing, int defaultSpacing) {
return customSpacing > -1 ? customSpacing : defaultSpacing;
}
/**
* 计算RecyclerView需要的总宽度(用于预计算item宽度)
* @param screenWidth 屏幕可用宽度
* @return 单个item的理论宽度
*/
public int getTotalWidthNeeded(int screenWidth) {
if (spanCount == 0) return screenWidth;
// 计算总间距 = 列间间距 + 边缘间距
int totalSpacing = (spanCount > 1) ? (spanCount - 1) * spacing : 0;
if (includeFirstColumnSpacing > 0) totalSpacing += spacing;
if (includeLastColumnSpacing > 0) totalSpacing += spacing;
// 返回单个item宽度 = (总宽度 - 总间距) / 列数
return (screenWidth - totalSpacing) / spanCount;
}
}
435

被折叠的 条评论
为什么被折叠?



