RecyclerView之利用ItemDecoration实现万能间距

目前在Android开发中RecyclerView的使用率依然很高,提到RecyclerView就绕不开Item间距的问题,说实话,我在刚开始接触RecyclerView时,是给布局里设置margin来实现间距的(捂脸。。。现在想来自己是多么无知),直到后来发现人家RecyclerView早已洞穿一切,给我们提供了一个方法addItemDecoration:

public void addItemDecoration(ItemDecoration decor) {
        addItemDecoration(decor, -1);
    }

其中参数ItemDecoration是RecyclerView的一个静态抽象内部类,需要我们继承它,然后重写getItemOffsets方法,在这个方法中去设置我们需要的间距。下面我把我重写的CommonItemDecoration分享给大家,在这里边我已经根据RecyclerView的列数或行数对不同item的间距进行了计算,我称之为“万能间距”!使用时只需传入你想要的间距大小即可,代码如下:

import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;

/**
 * Description:RecyclerView的万能间距
 * Created by kang on 2018/3/9.
 */
public class CommonItemDecoration extends RecyclerView.ItemDecoration {
    private int horizontalSpace; // 每个item左右两侧的间距
    private int verticalSpace; // 每个item上下的间距
    private int leftMargin; // 整个RecyclerView的左间距
    private int topMargin; // 整个RecyclerView的顶部间距
    private int rightMargin; // 整个RecyclerView的右间距
    private int bottomMargin; // 整个RecyclerView的底部间距

    public CommonItemDecoration(int horizontalSpace, int verticalSpace) {
        this(horizontalSpace, verticalSpace, 0, 0, 0, 0);
    }

    public CommonItemDecoration(int horizontalSpace, int verticalSpace, int margin) {
        this(horizontalSpace, verticalSpace, margin, margin, margin, margin);
    }

    public CommonItemDecoration(int horizontalSpace, int verticalSpace, int leftMargin, int topMargin, int rightMargin, int bottomMargin) {
        this.horizontalSpace = horizontalSpace;
        this.verticalSpace = verticalSpace;
        this.leftMargin = leftMargin;
        this.topMargin = topMargin;
        this.rightMargin = rightMargin;
        this.bottomMargin = bottomMargin;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        // 得到当前Item在RecyclerView中的位置,从0开始
        int position = parent.getChildAdapterPosition(view);
        // 得到RecyclerView中Item的总个数
        int count = parent.getAdapter().getItemCount();

        if (parent.getLayoutManager() instanceof GridLayoutManager) { // 网格布局
            GridLayoutManager gridLayoutManager = (GridLayoutManager) parent.getLayoutManager();
            // 得到网格布局的列数
            int spanCount = gridLayoutManager.getSpanCount();
            // 判断该网格布局是水平还是垂直
            if (LinearLayoutManager.VERTICAL == gridLayoutManager.getOrientation()) { // 垂直
                if (spanCount == 1) { // 列数为1
                    verticalColumnOne(outRect, position, count);
                } else { // 列数大于1
                    verticalColumnMulti(outRect, position, count, spanCount);
                }
            } else if (LinearLayoutManager.HORIZONTAL == gridLayoutManager.getOrientation()) { // 水平
                if (spanCount == 1) { // 行数为1
                    horizontalColumnOne(outRect, position, count);
                } else { // 行数大于1
                    horizontalColumnMulti(outRect, position, count, spanCount);
                }
            }
        } else if (parent.getLayoutManager() instanceof LinearLayoutManager) { // 线性布局
            LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
            if (LinearLayoutManager.VERTICAL == layoutManager.getOrientation()) { // 垂直
                verticalColumnOne(outRect, position, count);
            } else if (LinearLayoutManager.HORIZONTAL == layoutManager.getOrientation()) { // 水平
                horizontalColumnOne(outRect, position, count);
            }
        } else if (parent.getLayoutManager() instanceof StaggeredGridLayoutManager) { // 流布局
            //TODO 瀑布流布局相关
        }
    }

    /**
     * 列表垂直且列数为1
     *
     * @param outRect  包括左上右下四个参数,分别控制view左上右下的margin
     * @param position 当前view所处位置
     * @param count    RecyclerView中Item的总个数
     */
    private void verticalColumnOne(Rect outRect, int position, int count) {
        if (position == 0) { // 位置为0时(即第一个Item),不设置底部间距
            outRect.set(leftMargin, topMargin, rightMargin, 0);
        } else if (position == count - 1) { // 最后一个Item
            outRect.set(leftMargin, verticalSpace, rightMargin, bottomMargin);
        } else { // 中间的Item,不设置底部间距
            outRect.set(leftMargin, verticalSpace, rightMargin, 0);
        }
    }

    /**
     * 列表垂直且列数大于1
     *
     * @param outRect   包括左上右下四个参数,分别控制view左上右下的margin
     * @param position  当前view所处位置
     * @param count     RecyclerView中Item的总个数
     * @param spanCount 布局的列数
     */
    private void verticalColumnMulti(Rect outRect, int position, int count, int spanCount) {
        // 由于是网格布局,故每个item宽度是固定的,这里计算出每个item的左右边距之和
        int mEachSpace = (leftMargin + rightMargin + (spanCount - 1) * horizontalSpace) / spanCount;
        // 通过计算得出总行数
        int totalRow = count / spanCount + ((count % spanCount) == 0 ? 0 : 1);
        // 计算得出当前view所在的行
        int row = position / spanCount;
        int column = (position) % spanCount;
        int diff = ((mEachSpace - rightMargin) - leftMargin) / (spanCount - 1);
        int left = (column + 1 - 1) * diff + leftMargin;
        int right = mEachSpace - left;
        if (row == 0) {
            outRect.set(left,
                    topMargin,
                    right,
                    0);
        } else if (row == totalRow - 1) {
            outRect.set(left,
                    0,
                    right,
                    bottomMargin);
        } else {
            outRect.set(left,
                    0,
                    right,
                    verticalSpace);
        }
    }

    /**
     * 列表水平且行数为1
     *
     * @param outRect  包括左上右下四个参数,分别控制view左上右下的margin
     * @param position 当前view所处位置
     * @param count    RecyclerView中Item的总个数
     */
    private void horizontalColumnOne(Rect outRect, int position, int count) {
        if (position == 0) { // 位置为0时(即第一个Item)
            outRect.set(leftMargin, topMargin, horizontalSpace / 2, bottomMargin);
        } else if (position == count - 1) { // 最后一个Item
            outRect.set(horizontalSpace / 2, topMargin, rightMargin, bottomMargin);
        } else { // 中间的Item
            outRect.set(horizontalSpace / 2, topMargin, horizontalSpace / 2, bottomMargin);
        }
    }

    /**
     * 列表水平且行数大于1
     *
     * @param outRect   包括左上右下四个参数,分别控制view左上右下的margin
     * @param position  当前view所处位置
     * @param count     RecyclerView中Item的总个数
     * @param spanCount 布局的行数
     */
    private void horizontalColumnMulti(Rect outRect, int position, int count, int spanCount) {
        // 通过计算得出总列数
        int totalColumn = count / spanCount + ((count % spanCount) == 0 ? 0 : 1);
        // 计算得出当前view所在的列
        int column = position / spanCount;
        // 通过对position加1对spanCount取余得到row
        // 保证row等于1为第一行,等于0为最后一个,其它值为中间行
        int row = (position + 1) % spanCount;
        if (row == 1) {
            outRect.set(column == 0 ? leftMargin : horizontalSpace / 2,
                    topMargin,
                    column == totalColumn - 1 ? rightMargin : horizontalSpace / 2,
                    0);
        } else if (row == 0) {
            outRect.set(column == 0 ? leftMargin : horizontalSpace / 2,
                    verticalSpace,
                    column == totalColumn - 1 ? rightMargin : horizontalSpace / 2,
                    bottomMargin);
        } else {
            outRect.set(column == 0 ? leftMargin : horizontalSpace / 2,
                    verticalSpace,
                    column == totalColumn - 1 ? rightMargin : horizontalSpace / 2,
                    0);
        }
    }

}

若想实现分割线效果,看我的下一篇文章!

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值