自定义RecyclerView的ItemDecoration,用于处理网格布局间距装饰器(支持边缘间距独立控制)

自定义RecyclerView的ItemDecoration,用于处理网格布局的间距,网格布局间距装饰器(支持边缘间距独立控制),为RecyclerView网格布局提供灵活的间距控制,可单独设置各边缘间距。

核心功能说明:

  1. 灵活的边缘控制:可单独设置首列/末列/首行/末行的间距
  2. 智能间距分配:
  • 多列布局时自动将间距平分到相邻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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值