android BaseRecyclerViewApapter GridLayoutManager 实现列数不同的对称排列

要求 效果图 如下,带删除功能

简单的可以使用 LinearLayout 来实现,但删除什么的也不好弄

最终还是用  RecyclerView + GridLayoutManager 实现,,,,

实现思路是:::  一.用  addItemDecoration 方法来实现不同的间距,,,,没有成功....

二用, 多RecyclerView 的多类型item (就是第二行的第一个添加marginLeft 和最后一个添加marginRight) 与 SpanSizeLookup 变化实现

代码如下:::

recyclerView.apply {
                adapter = viewModel.headAdapter
                viewModel.headAdapter.bindToRecyclerView(this)
                // 20 一行的总份额
                layoutManager = GridLayoutManager(requireContext(), 20).apply {
                    spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
                        override fun getSpanSize(position: Int): Int {
                            // 每个item 所占份额
                            return firstMap[position]!!
                        }
                    }
                }
            }
firstMap = 
/**
     *  list count 总个数
     *  return  HashMap 在index位置的item应该占有的份额
     */
    private fun getMapByPosition(count: Int): HashMap<Int, Int> {
        val firstMap = HashMap<Int, Int>()
        var isChange = true  // true 取 put 4 fase put 5
        // 行个数
        val oneSpanNum = 4 // 总份额20 / 每个item占4份额 = 每行显示5个item
        val twoSpanNum = 5 // 总份额20 / 每个item占5份额 = 每行显示4个item
        var countNun = twoSpanNum
        for (position in 0..count) {
            if (position < countNun) {
                if (isChange) {
                    firstMap.put(position, oneSpanNum)
                } else {
                    firstMap.put(position, twoSpanNum)
                }
            } else {
                isChange = !isChange
                if (isChange) {
                    countNun += twoSpanNum
                    firstMap.put(position, oneSpanNum)
                } else {
                    countNun += oneSpanNum
                    firstMap.put(position, twoSpanNum)
                }
            }
        }
        return firstMap
    }

在http接收到要显示的数据时,要处理一下

 /**
     * 模拟 http 返回数据
     */
    fun testHeadBeanData(): ArrayList<TestResponseBean> {
        val listBeans = ArrayList<TestResponseBean>()
        for (index in 0..20) {
            listBeans.add(TestResponseBean("王-$index"))
        }
        return listBeans
    }

    /**
     * firstMap.size = listBeans.size 总数要相等
     */
    fun testHeadData(
        firstMap: HashMap<Int, Int>, listBeans: List<TestResponseBean> = testHeadBeanData()
    ): HashMap<Int, Int> {
        var isChange = true
        val maxLineNum = 4 //判断是偶数还是奇数
        var rightIndex = 0 //标记偶数行的最后一个的位置
        var oldNum = 0 //
        for ((index, value) in firstMap) {
            // 初始化
            if (isChange && oldNum == 0) {
                isChange = !isChange
                oldNum = value
            }
            // 如果相等
            if (value == oldNum) {
                observableHeadList.add(listBeans[index])
                if (index < rightIndex) {
                    // 将偶数行 中间的item 份额 -1 用来调整间距
                    firstMap.put(index, value - 1)
                } else if (rightIndex == index && rightIndex != 0) {
                    //因为在上面的第五行代码已经添加了相同 index的bean
                    observableHeadList.removeAt(observableHeadList.size - 1)
                    val bean = listBeans[index].apply { mItemType = 2 }
                    observableHeadList.add(bean)
                    // 将偶数行 两边的item 份额 +1 用来调整间距
                    firstMap.put(index, value + 1)
                }
            } else {
                if (!isChange && value != maxLineNum) {
                    // 切换到 偶数行的第一个
                    val bean = listBeans[index].apply { mItemType = 1 }
                    observableHeadList.add(bean)
                    firstMap.put(index, value + 1)
                    // 计算 偶数行 的最后一个的位置
                    if (index + value - 2 < firstMap.size) {
                        rightIndex = index + value - 2
                    }
                } else {
                    observableHeadList.add(listBeans[index])
                }
                isChange = !isChange
                oldNum = value

            }
        }
        return firstMap
    }
使用的是 CymChadBaseRecyclerViewApapter的框架
TestResponseBean 
data class TestResponseBean(
    val title: String? = "",
    val time1: String? = "",
    val timeCount: Float? = 0f,
    var isSel: Boolean = false,
    var isSwitched: Boolean = false,
    val position: Int = 0,
    val marginLeft:Float = 0f,
    val marginRight:Float = 0f,
    var mItemType:Int = 0 // 多itemType中 属于哪一个
) :  MultiItemEntity{
    override fun getItemType(): Int {
        return mItemType
    }}
RecyclerVMultTypeCommonAdapter
class RecyclerVMultTypeCommonAdapter(
    @LayoutRes private val itemLayouts: List<Int>, // 按顺序传入 R.layout.xxx <第一层BR,第二层BR
    @IdRes private val brIds: List<Int>, //按顺序传入 BR.xxxx  <第一层BR,第二层BR
    data: List<MultiItemEntity>, private val itemBindingCallBack: ItemBindingCallBack? = null // 回调 用来改变转向图标,自定义一些东西
) : BaseMultiItemQuickAdapter<MultiItemEntity, BaseViewHolder>(data) {

    init {
        for ((index, layoutId) in itemLayouts.withIndex()) {
            addItemType(index, layoutId)
        }
    }

    private var lifecycleOwner: LifecycleOwner? = null

    override fun convert(
        holder: BaseViewHolder, item: MultiItemEntity
    ) {
        for ((index, layoutId) in itemLayouts.withIndex()) {
            if (holder.itemViewType == index) {
                //                mViewHolder[index].invoke(helper, item)
                // This won't be called by recyclerview since we are overriding the other overload, call
                // the other overload here in case someone is calling this directly ex: in a test.
                var binding = DataBindingUtil.getBinding<ViewDataBinding>(holder.itemView)
                if (binding == null) {
                    binding = DataBindingUtil.bind(holder.itemView)
                }
                binding?.let {
                    onBindBinding(
                        it, brIds[index], layoutId, item
                    )
                }
                binding?.let { it1 -> itemBindingCallBack?.invoke(holder, it1, item) }
            }
        }
    }

   /* override fun getItemView(@LayoutRes layoutResId: Int, parent: ViewGroup): View {
        val binding =
            DataBindingUtil.inflate<ViewDataBinding>(LayoutInflater.from(parent.context), layoutResId, parent, false)
            ?: return super.getItemView(layoutResId, parent)
        //        return new BindingHolder(binding);
        val view = binding.root
        view.setTag(R.id.BaseQuickAdapter_databinding_support, binding)
        return view
    }*/

    private fun onBindBinding(
        binding: ViewDataBinding, br: Int, layoutId: Int, item: MultiItemEntity
    ) {
        tryGetLifecycleOwner()

        if (binding.setVariable(br, item)) {
            binding.executePendingBindings()
            if (lifecycleOwner != null) {
                binding.lifecycleOwner = lifecycleOwner
            }
        }
    }

    private fun tryGetLifecycleOwner() {
        if (lifecycleOwner == null || lifecycleOwner!!.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
            lifecycleOwner = findLifecycleOwner(recyclerView)
        }
    }


    // https://github.com/CymChad/BaseRecyclerViewAdapterHelper/blob/master/README-cn.md
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
        return super.onCreateViewHolder(parent, viewType)
    }

    /**
     * 从 bindingCollectionadapter2-3.1.1中BindingRecyclerViewAdapter 复制
     * Returns the lifecycle owner associated with the given view. Tries to get lifecycle owner first
     * from ViewDataBinding, else from View Context if view is not data-bound.
     */
    @MainThread
    fun findLifecycleOwner(view: View): LifecycleOwner? {
        val binding = DataBindingUtil.findBinding<ViewDataBinding>(view)
        var lifecycleOwner: LifecycleOwner? = null
        if (binding != null) {
            lifecycleOwner = binding.lifecycleOwner
        }
        val ctx = view.context
        if (lifecycleOwner == null && ctx is LifecycleOwner) {
            lifecycleOwner = ctx
        }
        return lifecycleOwner
    }

}
原文地址:https://www.cnblogs.com/caosq/p/12060921.html