Android: RecyclerView的GridLayout布局前后两列靠屏幕左右两边展示,中间列对剩余空间进行平分展示

1,133 阅读3分钟

RecyclerView的GridLayout布局前后两列靠边、中间列平分展示

说明:图中的第一个列表及第二个列表

第一个列表(1-5)展示的是GridLayut布局对子项不做任何修饰时,子项平分展示

第二个列表(1-5)展示的是GridLayou布局前后两列靠左右两边,中间列进行平分展示

竖屏展示效果如下:

Screenshot_20230226_103814.jpg

横屏展示效果如下:

Screenshot_20230226_103826.jpg

1、列表子项的布局

给布局的背景添加了一个红色的线圈,便于观察如何分割空间

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/item_background">

    <TextView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/item_tv"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:visibility="visible"
        android:text=""
        android:gravity="center"
        android:textSize="18sp"
        android:textColor="@color/white"
        android:layout_margin="1dp"/>

</RelativeLayout>

布局的背景如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/white" />
    <stroke
        android:width="1dp"
        android:color="@color/red" />
</shape>

2、GridLayut布局对子项不做任何修饰时,子项平分展示

如上图中的第一个列表所示,每个列表子项所占据的空间是平分当前屏幕的。

仅仅是将RecyclerView的LayoutManger设置为GridLayoutManager,就起到每个子项平分当前屏幕的效果。

mRecyclerView.setLayoutManager(new GridLayoutManager(mContext, 5));
mRecyclerView.setAdapter(adapter);

3、通过实现ItemDecoration,前后两列靠边,中间列平分展示

(1)推导过程

对于图中的第二行列表所示,前后两列靠屏幕的左右两边展示,中间列进行平分空间展示。

通过图中的第一行列表和第二行列表对比能够看出,想要实现上述的效果:

对于第二行列表 相较于 第一行列表而言

  • 对于子项1,向右偏移红色框中白色空间的0/4

  • 对于子项2,向右偏移红色框中白色空间的1/4

  • 对于子项3,向右偏移红色框中白色空间的2/4

  • 对于子项4,向右偏移红色框中白色空间的3/4

  • 对于子项5,向右偏移红色框中白色空间的4/4

对上面内容进行拆解下

拆解一:

对于子项,可以拿到position,子项1-5对应的position是0 - 4,因此对每一项而言:

向右偏移了position * (红色框中白色空间的1/4)

拆解二:

红色框中白色空间:(当前屏幕 - 每个子项TextView所占空间 * 5 )/ 5

这里的当前屏幕 - 每个子项所占空间 * 5 实际就是当前的剩余空间,用totalRemainSpace变量表示

将拆解一及拆解二合并下:

向右偏移:position * (totalRemainSpace / 5 * 1/4)

(2)计算公式

通过position * (totalRemainSpace / 5 * 1/4) 再进一步推导可得:mSpanCount变量表示5

position * totalRemainSpace / (mSpanCount * (mSpanCount - 1))

或者:

position * (totalRemainSpace / (mSpanCount - 1) - totalRemainSpace / mSpanCount)

说明:这里的5表示的是列数,上面的每个子项所占空间是指布局中的TextView

(3)代码实现

向右偏移: 实际就是指子项布局的矩形的left值

即通过实现继承ItemDecoration,重写getItemOffsets方法来改变每个子项布局中的left值,代码如下

@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent,
                           @NonNull RecyclerView.State state) {
    // 这里的 mSpanCount 是指:Grid布局的列数,mDp36 是指:item(TextView)的宽度
    int position = parent.getChildAdapterPosition(view) % mSpanCount;

    // 当前屏幕宽度
    int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;

    // 前后item靠左右两边,其余的item平分剩余空间
    int totalRemainSpace = screenWidth - mSpanCount * mDp36;

    outRect.left = position * (totalRemainSpace / (mSpanCount - 1)  -   totalRemainSpace / mSpanCount);

}

RecyclerView设置ItemDecoration即可:DivideSpaceItemDecoration 是继承 ItemDecoration 的实现类

mRecyclerView.addItemDecoration(new DivideSpaceItemDecoration(mContext, 5));
mRecyclerView.setLayoutManager(new GridLayoutManager(mContext, 5));
mRecyclerView.setAdapter(adapter);