• RecyclerView使用GridLayoutManager 设置间距一致大小


    在android应用中,要实现一个Recycleview,使用GridLayoutManager格子排列,且排列成4列
    实现水平方向间距均等(没有外边距)。

    (均分为3列5列等、竖直方向、有边距等原理相同。)

    先看最终效果图。


    ---
    xml中这样配置

    1. <androidx.recyclerview.widget.RecyclerView
    2.     android:background="#bbffbb"
    3.     android:layout_width="match_parent"
    4.     android:layout_height="wrap_content"
    5.     app:spanCount="4"
    6.     tools:listitem="@layout/layout_item"/>

    为了醒目,我们让RecyclerView背景是浅绿色。


    每一个item的配置如layout_item.xml所示

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3.     xmlns:app="http://schemas.android.com/apk/res-auto"
    4.     xmlns:tools="http://schemas.android.com/tools"
    5.     android:layout_width="wrap_content"
    6.     android:background="#ffcccc"
    7.     android:layout_height="wrap_content">
    8.     <TextView
    9.         android:id="@+id/name"
    10.         android:layout_width="0dp"
    11.         android:layout_height="wrap_content"
    12.         android:layout_marginTop="8dp"
    13.         android:gravity="center"
    14.         android:textSize="12sp"
    15.         app:layout_constraintEnd_toEndOf="@+id/thumb"
    16.         app:layout_constraintStart_toStartOf="@+id/thumb"
    17.         app:layout_constraintTop_toBottomOf="@+id/thumb"
    18.         tools:text='NAME' />
    19.     <com.google.android.material.imageview.ShapeableImageView
    20.         android:id="@+id/thumb"
    21.         android:layout_width="65dp"
    22.         android:layout_height="65dp"
    23.         android:scaleType="fitXY"
    24.         app:layout_constraintEnd_toEndOf="parent"
    25.         app:layout_constraintStart_toStartOf="parent"
    26.         app:layout_constraintTop_toTopOf="parent"
    27.         tools:background="@drawable/item_bg" />
    28. </androidx.constraintlayout.widget.ConstraintLayout>

    为了醒目,我们让每一个item的背景色为浅红色。

    Activity中,我们这样设置

    1. class MyItemDecorator:RecyclerView.ItemDecoration(){
    2.     val spanCount = 4
    3.     override fun getItemOffsets(
    4.         outRect: Rect,
    5.         view: View,
    6.         parent: RecyclerView,
    7.         state: RecyclerView.State
    8.     ) {
    9.         val position = parent.getChildAdapterPosition(view)
    10.         val column =position% spanCount //第几列
    11.     }
    12. }
    13.         binding.recycleHot.addItemDecoration(MyItemDecorator())

    这样的显示效果,就是,最左边item的左边距离0,最右边item的右边距离不是0。




    如果layout_item.xml里root布局

     android:layout_width="match_parent"

    显示效果为:

     ---

    在函数

    1. getItemOffsets(
    2.         outRect: Rect,
    3.         view: View,
    4.         parent: RecyclerView,
    5.         state: RecyclerView.State
    6.     )


        view.width始终是0,不管item的root布局layout_widht是match_parent还是wrap_content。
        

    ---
    终极解法 ,

     

    我们设每个item的左右边距分别是L0、R0、L1、R1、L2、R2、L3、R3。


     

    我们要求边距相同,即 

    R0+L1 =  R1+L2 = R2+L3 = space(间距)    

    每一个item占的地方是一样的,即

    L0+item内宽度+R0 = item外宽度

    L1+item内宽度+R1 = item外宽度

    L2+item内宽度+R2 = item外宽度

    L3+item内宽度+R3 = item外宽度

    L0+R0 = L1+R1 = L2+R2 = L3+R3 = item外宽度-item内宽度          (设为p)


    我们知道L0==R3==0
    故可以推算出

    L0 = 0
    R0 = p-L0= p
    L1 = space - R0 = space-p
    R1 = p-L1 = p-(space-p) =  p*2 -space
    L2 = space -R1 = sapce - (p*2-space) = space*2 - p*2(根据对称==R1==p*2-space)
    R2 = p-L2 = p-(space*2-p*2) = p*3 - space*2(根据对称==L1==space-p)
    L3 = space-R2 = space-(p*3-space*2) = space*3 -p*3(根据对称==R0==p)
    R3 = 0

    据此,

    改善代码   

    1. class MyItemDecorator : RecyclerView.ItemDecoration() {
    2.         val spanCount = 4
    3.         override fun getItemOffsets(
    4.             outRect: Rect,
    5.             view: View,
    6.             parent: RecyclerView,
    7.             state: RecyclerView.State
    8.         ) {
    9.             val position = parent.getChildAdapterPosition(view)
    10.             val column = position % spanCount
    11.             fun dp2px(dp: Int): Int {
    12.                 val scale = view.resources.displayMetrics.density
    13.                 return (dp * scale + 0.5f).toInt()
    14.             }
    15.             val itemWidth = parent.width / 4  //item外宽度
    16.             val itemWidthInside = dp2px(65) //item内宽度
    17.             val padding = itemWidth - itemWidthInside // p
    18.             val space = (parent.width - 4 * itemWidthInside) / 3 // space
    19.             if (column == 0) {
    20.                 outRect.left = 0
    21.                 outRect.right = padding
    22.             } else if (column == 1) {
    23.                 outRect.left = space - (padding)
    24.                 outRect.right = padding * 2 - space
    25.             } else if (column == 2) {
    26.                 outRect.left = space * 2 - padding * 2
    27.                 outRect.right = padding * 3 - space * 2
    28.             } else if (column == 3) {
    29.                 outRect.left = padding
    30.                 outRect.right = 0
    31.             }
    32.         }
    33.     }

    layout_item.xml也要改,把root组件的layout_width固定。

    android:layout_width="65dp"

    这样就能实现GridLayoutManager是4列排布,各个item间距相同,最左边和最右边的item距离边框距离为0的效果。

     

    如果RecycleView里设置了padding,比如

    1. ```
    2.             <androidx.recyclerview.widget.RecyclerView
    3.                 android:background="#bbffbb"
    4. +               android:paddingHorizontal="16dp"
    5.                 android:layout_width="match_parent"
    6.                 android:layout_height="wrap_content"
    7.                 app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
    8.                 app:spanCount="4"
    9.                 tools:listitem="@layout/layout_item"/>

    此时,应该在Activity中,要把parent.Width改为parent.Width - parent.paddingLeft -parent.paddingRight

    1.   override fun getItemOffsets(
    2.         outRect: Rect,
    3.         view: View,
    4.         parent: RecyclerView,
    5.         state: RecyclerView.State
    6.     ) {
    7.         val position = parent.getChildAdapterPosition(view)
    8.         val column = position % spanCount
    9.         fun dp2px(dp: Int): Int {
    10.             val scale = view.resources.displayMetrics.density
    11.             return (dp * scale + 0.5f).toInt()
    12.         }
    13.         val parentWidth = parent.width - parent.paddingLeft - parent.paddingRight
    14.         val itemWidth = parentWidth / 4
    15.         val itemWidthInside = dp2px(65)
    16.         val padding = itemWidth - itemWidthInside
    17.         val space = (parentWidth - 4 * itemWidthInside) / 3
    18.         when (column) {
    19.             0 -> {
    20.                 outRect.left = 0
    21.                 outRect.right = padding
    22.             }
    23.             1 -> {
    24.                 outRect.left = space - (padding)
    25.                 outRect.right = padding * 2 - space
    26.             }
    27.             2 -> {
    28.                 outRect.left = space * 2 - padding * 2
    29.                 outRect.right = padding * 3 - space * 2
    30.             }
    31.             3 -> {
    32.                 outRect.left = padding
    33.                 outRect.right = 0
    34.             }
    35.         }
    36.     }

    效果为

     

  • 相关阅读:
    18.Redis系列之AOF方式持久化
    HBase简介
    Idea创建JavaEE项目
    Actipro WPF Controls 22.1.3 -new-注册版
    HTML二识
    python paramiko模块
    高性能云原生数据对象存储MinIO实战-中
    行业轮动从动量因子说起
    创建线程的方式打开记事本
    【无标题】
  • 原文地址:https://blog.csdn.net/coraline1991/article/details/125427892