带有Recycler的双粘性割台查看物品摆件

问题描述

如何使用Itemdecoration为Android Recyclerview做双层粘性标头?我有3种类型的视图:2个标题和1个项目(子项)视图。我需要类似link

功能
dataBinding.recyclerView.addItemdecoration(HeaderItemdecoration(dataBinding.recyclerView) { itemPosition ->
            if (itemPosition >= 0 && itemPosition < dataBinding.recyclerView.adapter!!.itemCount) {
                val viewType = dataBinding.recyclerView.adapter!!.getItemViewType(itemPosition)
                viewType == VIEW_TYPE_HEADER_1
            } else false
        })

这是我的HeaderItemdecoration

class HeaderItemdecoration(parent: RecyclerView,private val shouldFadeOutHeader: Boolean = false,private val isHeader: (itemPosition: Int) -> Boolean) : RecyclerView.Itemdecoration() {
    
        private var currentHeader: Pair<Int,RecyclerView.ViewHolder>? = null
    
        init {
            parent.adapter?.registeradapterDataObserver(object : RecyclerView.AdapterDataObserver() {
                override fun onChanged() {
                    // clear saved header as it can be outdated Now
                    currentHeader = null
                }
            })
    
            parent.doOnEachNextLayout {
                // clear saved layout as it may need layout update
                currentHeader = null
            }
            // handle click on sticky header
            parent.addOnItemTouchListener(object : RecyclerView.SimpleOnItemTouchListener() {
                override fun onInterceptTouchEvent(
                        recyclerView: RecyclerView,motionEvent: MotionEvent
                ): Boolean {
                    return if (motionEvent.action == MotionEvent.ACTION_DOWN) {
                        motionEvent.y <= currentHeader?.second?.itemView?.bottom ?: 0
                    } else false
                }
            })
        }
    
        override fun onDrawOver(c: Canvas,parent: RecyclerView,state: RecyclerView.State) {
            super.onDrawOver(c,parent,state)
            //val topChild = parent.getChildAt(0) ?: return
            val topChild = parent.findChildViewUnder(
                    parent.paddingLeft.toFloat(),parent.paddingTop.toFloat() /*+ (currentHeader?.second?.itemView?.height ?: 0 )*/
            ) ?: return
            val topChildPosition = parent.getChildAdapterPosition(topChild)
            if (topChildPosition == RecyclerView.NO_POSITION) {
                return
            }
    
            val headerView = getHeaderViewForItem(topChildPosition,parent) ?: return
    
            val contactPoint = headerView.bottom + parent.paddingTop
            val childInContact = getChildInContact(parent,contactPoint) ?: return
    
            if (isHeader(parent.getChildAdapterPosition(childInContact))) {
                moveHeader(c,headerView,childInContact,parent.paddingTop)
                return
            }
    
            drawHeader(c,parent.paddingTop)
        }
    
        private fun getHeaderViewForItem(itemPosition: Int,parent: RecyclerView): View? {
            if (parent.adapter == null) {
                return null
            }
            val headerPosition = getHeaderPositionForItem(itemPosition)
            if (headerPosition == RecyclerView.NO_POSITION) return null
            val headerType = parent.adapter?.getItemViewType(headerPosition) ?: return null
            // if match reuse viewHolder
            if (currentHeader?.first == headerPosition && currentHeader?.second?.itemViewType == headerType) {
                return currentHeader?.second?.itemView
            }
    
            val headerHolder = parent.adapter?.createViewHolder(parent,headerType)
            if (headerHolder != null) {
                parent.adapter?.onBindViewHolder(headerHolder,headerPosition)
                fixLayoutSize(parent,headerHolder.itemView)
                // save for next draw
                currentHeader = headerPosition to headerHolder
            }
            return headerHolder?.itemView
        }
    
        private fun drawHeader(c: Canvas,header: View,paddingTop: Int) {
            c.save()
            c.translate(0f,paddingTop.toFloat())
            header.draw(c)
            c.restore()
        }
    
        private fun moveHeader(c: Canvas,currentHeader: View,nextHeader: View,paddingTop: Int) {
            c.save()
            if (!shouldFadeOutHeader) {
                c.clipRect(0,paddingTop,c.width,paddingTop + currentHeader.height)
            } else {
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                    c.saveLayerAlpha(
                            RectF(0f,0f,c.width.toFloat(),c.height.toFloat()),(((nextHeader.top - paddingTop) / nextHeader.height.toFloat()) * 255).toInt()
                    )
                } else {
                    c.saveLayerAlpha(
                            0f,c.height.toFloat(),(((nextHeader.top - paddingTop) / nextHeader.height.toFloat()) * 255).toInt(),Canvas.ALL_SAVE_FLAG
                    )
                }
    
            }
            c.translate(0f,(nextHeader.top - currentHeader.height).toFloat() /*+ paddingToP*/)
    
            currentHeader.draw(c)
            if (shouldFadeOutHeader) {
                c.restore()
            }
            c.restore()
        }
    
        private fun getChildInContact(parent: RecyclerView,contactPoint: Int): View? {
            var childInContact: View? = null
            for (i in 0 until parent.childCount) {
                val child = parent.getChildAt(i)
                val mBounds = Rect()
                parent.getDecoratedBoundsWithMargins(child,mBounds)
                if (mBounds.bottom > contactPoint) {
                    if (mBounds.top <= contactPoint) {
                        // This child overlaps the contactPoint
                        childInContact = child
                        break
                    }
                }
            }
            return childInContact
        }
    
        /**
         * Properly measures and layouts the top sticky header.
         *
         * @param parent ViewGroup: RecyclerView in this case.
         */
        private fun fixLayoutSize(parent: ViewGroup,view: View) {
    
            // Specs for parent (RecyclerView)
            val widthSpec = View.MeasureSpec.makeMeasureSpec(parent.width,View.MeasureSpec.EXACTLY)
            val heightSpec =
                    View.MeasureSpec.makeMeasureSpec(parent.height,View.MeasureSpec.UNSPECIFIED)
    
            // Specs for children (headers)
            val childWidthSpec = ViewGroup.getChildMeasureSpec(
                    widthSpec,parent.paddingLeft + parent.paddingRight,view.layoutParams.width
            )
            val childHeightSpec = ViewGroup.getChildMeasureSpec(
                    heightSpec,parent.paddingTop + parent.paddingBottom,view.layoutParams.height
            )
    
            view.measure(childWidthSpec,childHeightSpec)
            view.layout(0,view.measuredWidth,view.measuredHeight)
        }
    
        private fun getHeaderPositionForItem(itemPosition: Int): Int {
            var headerPosition = RecyclerView.NO_POSITION
            var currentPosition = itemPosition
            do {
                if (isHeader(currentPosition)) {
                    headerPosition = currentPosition
                    break
                }
                currentPosition -= 1
            } while (currentPosition >= 0)
            return headerPosition
        }
    }
    
    inline fun View.doOnEachNextLayout(crossinline action: (view: View) -> Unit) {
        addOnLayoutchangelistener { view,_,_ ->
            action(
                    view
            )
        }
    }

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...