zoukankan      html  css  js  c++  java
  • 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
        }
    
    }
  • 相关阅读:
    ps中的一些方法
    extjs 横向滚动条 和 本地排序
    JS JSON.parse() 和 JSON.stringify()
    SQL 同一个表中 根据一列更新另一列(不同行)
    extjs2.2 panel加背景色
    extjs2.2 combo的监听
    ExtJS2.2 form表单提交时不提交emptyText
    Extjs 复制对象
    Extjs 显示或隐藏滚动条
    Extjs2.2 开始时间,结束时间,工期 联动(选二补一),包含日期,天数的互转
  • 原文地址:https://www.cnblogs.com/caosq/p/12060921.html
Copyright © 2011-2022 走看看