Aliquots pitch RecyclerView GridLayoutManager

RecyclerView table to achieve

RecyclerView GridLayoutManager with table-like style can be achieved, in order to achieve sharing, Adapter width to match the layout of the parent element, i.e., android: layout_width = "match_parent".

RecyclerView rvPhotoAlbums = findViewById(R.id.rv_photoAlbums_content);
rvPhotoAlbums.setLayoutManager(new GridLayoutManager(this, 4));
rvPhotoAlbums.setAdapter(new PhotoAlbumsAdapter());

The effect is as follows:

Add spacing ItemDecoration

ItemDecoration source code analysis

androidx.recyclerview.widget.RecyclerView # addItemDecoration (androidx.recyclerview.widget.RecyclerView.ItemDecoration).
Briefly look ItemDecoration in the method:

public abstract static class ItemDecoration {
    // ....省略其他方法介绍.....

    /**
     * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies
     * the number of pixels that the item view should be inset by, similar to padding or margin.
     * The default implementation sets the bounds of outRect to 0 and returns.
     * 解读:获取给定item view的偏移量,用outRect 表示。outRect的每个字段分别表示不同方向的偏移量,类似于填充或边距。
     * 默认设置为0,即没有间距。
     *
     * <p>
     * If this ItemDecoration does not affect the positioning of item views, it should set
     * all four fields of <code>outRect</code> (left, top, right, bottom) to zero
     * before returning.
     * 如果不想影响item view 的位置,需要置outRect 的left, top, right, bottom 为0
     *
     * <p>
     * If you need to access Adapter for additional data, you can call
     * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the
     * View.
     *
     * @param outRect Rect to receive the output.
     * @param view    The child view to decorate
     * @param parent  RecyclerView this ItemDecoration is decorating
     * @param state   The current state of RecyclerView.
     */
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
            @NonNull RecyclerView parent, @NonNull State state) {
        getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
                parent);
    }
}

We know that through code comments, can handle the distance through inheritance androidx.recyclerview.widget.RecyclerView.ItemDecoration class.

Custom ItemDecoration

public class GridSpaceItemDecoration extends RecyclerView.ItemDecoration {

    private int mSpanCount;//横条目数量
    private int mRowSpacing;//行间距
    private int mColumnSpacing;// 列间距

    /**
     * @param spanCount     列数
     * @param rowSpacing    行间距
     * @param columnSpacing 列间距
     */
    public GridSpaceItemDecoration(int spanCount, int rowSpacing, int columnSpacing) {
        this.mSpanCount = spanCount;
        this.mRowSpacing = rowSpacing;
        this.mColumnSpacing = columnSpacing;
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view); // 获取view 在adapter中的位置。
        int column = position % mSpanCount; // view 所在的列

        // 列间距
        outRect.left = mColumnSpacing;

        // 如果position > 行数,说明不是在第一行,则不指定行高,其他行的上间距为 top=mRowSpacing
        if (position >= mSpanCount) {
            outRect.top = mRowSpacing; // item top
        }
    }
}

Add ItemDecoration

// 添加间距
rvPhotoAlbums.addItemDecoration(new GridSpaceItemDecoration(4,
        DpPxSpTool.INSTANCE.dip2px(this, 30),
        DpPxSpTool.INSTANCE.dip2px(this, 20)));

ok, we look at the effect of:

(Note: In order to distinguish the item view range, I use different colors to identify the stroke)
can be seen, item overall right, because GridLayoutManager width have been allocated to the Item, while we ItemDecoration the item view to set the left margin, so there will be a whole-right, squeeze the contents of the case.

Aliquots pitch

Realization of ideas

In order to achieve the same pitch, we need to set the left and right margins of the item, and the left side view of the right margin column pitch + view = left margin setting, the visual effect from the pitch appears to be equally divided.

First to sort out the conditions to be met like pitches:

  1. Equal size of each module, i.e. each row left + right values ​​are equal;
  2. It is equal to the pitch of the columns, i.e. the forefront of the right + left = column after column spacing;

Column spacing of 10 is assumed, for convenience of identification, in place of the column of the letter I.
In Case 2:

Check Condition 1: a.left + a.right = b.left + b.right = 5 Results: satisfies
Check Condition 2: a.right + b.left = 10 Results: meet

In Case 3:

Check Condition 1: a.left + a.right = b.left + b.right = c.left + c.right ≈ 6.66 Results: satisfies
Check Condition 2: a.right + b.left = b.right + c.left ≈ 10 results: meet

The inference can be drawn equation:
number of columns in a column where the left = * (column pitch * (1 / number of columns))
for a column right = row spacing - left column after column spacing = - number of columns (where +1) * (* column pitch (1 / number of columns))
Note: the number of the column where as used herein is from 0

Ultimately

/**
 * 描述 : RecyclerView GridLayoutManager 等间距。
 * <p>
 * 等间距需满足两个条件:
 * 1.各个模块的大小相等,即 各列的left+right 值相等;
 * 2.各列的间距相等,即 前列的right + 后列的left = 列间距;
 * <p>
 * 在{@link #getItemOffsets(Rect, View, RecyclerView, RecyclerView.State)} 中针对 outRect 的left 和right 满足这两个条件即可
 * <p>
 * 作者 : shiguotao
 * 版本 : V1
 * 创建时间 : 2020/3/19 4:54 PM
 */
public class GridSpaceItemDecoration extends RecyclerView.ItemDecoration {

    private final String TAG = "GridSpaceItemDecoration";

    private int mSpanCount;//横条目数量
    private int mRowSpacing;//行间距
    private int mColumnSpacing;// 列间距

    /**
     * @param spanCount     列数
     * @param rowSpacing    行间距
     * @param columnSpacing 列间距
     */
    public GridSpaceItemDecoration(int spanCount, int rowSpacing, int columnSpacing) {
        this.mSpanCount = spanCount;
        this.mRowSpacing = rowSpacing;
        this.mColumnSpacing = columnSpacing;
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view); // 获取view 在adapter中的位置。
        int column = position % mSpanCount; // view 所在的列

        outRect.left = column * mColumnSpacing / mSpanCount; // column * (列间距 * (1f / 列数))
        outRect.right = mColumnSpacing - (column + 1) * mColumnSpacing / mSpanCount; // 列间距 - (column + 1) * (列间距 * (1f /列数))

        Log.e(TAG, "position:" + position
                + "    columnIndex: " + column
                + "    left,right ->" + outRect.left + "," + outRect.right);

        // 如果position > 行数,说明不是在第一行,则不指定行高,其他行的上间距为 top=mRowSpacing
        if (position >= mSpanCount) {
            outRect.top = mRowSpacing; // item top
        }
    }
}

effect:

Once on shore, call it a day!

Published 22 original articles · won praise 44 · Views 100,000 +

Guess you like

Origin blog.csdn.net/JM_beizi/article/details/105364227