要求 效果图 如下,带删除功能
简单的可以使用 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 } }