Recyclerview: listen to padding click events

只愿长相守 提交于 2019-12-23 06:59:21

问题


I have an horizontal RecyclerView with leftPadding = 48dp, topPadding = 24dp and clipToPadding = false. It starts with an empty space on the left, but when the user scrolls the list its items are drawn on that (previously empty) space. The top space is always empty.

This RecyclerView is inside a FrameLayout with foreground = selectableItemBackground.

My problem comes from the fact that the RecyclerView consumes and ignores touches on the left and top spaces, meaning an OnClickListener won't be triggered, both when attached to the FrameLayout or to the RecyclerView.

I already tried with clickable = false and focusable = false on the RecyclerView, it doesn't work.

What I'm looking for:

  1. Scrollable RecyclerView
  2. Clickable RecyclerView items
  3. FrameLayout click events when RecyclerView's empty spaces are clicked
  4. (alternative to 3) Clickable RecyclerView's empty spaces

EDIT: I've created a simple project that shows the problem I'm talking about: https://github.com/dadino/recyclerviewemptyspacestest There are 2 commits, on the first one I try to catch the click on the parent view, on the second one I try to catch the click on the RecyclerView itself. Neither of them works.


回答1:


You have to create your custom RecyclerView implementation, where you would listen to touch events and perform filtering based on that.

class MyRecyclerView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : RecyclerView(context, attrs, defStyleAttr) {

    private var isValid = false
    private var x: Int = 0
    private var y: Int = 0
    // this will help us to understand whether the event can be considered a touch or scroll
    private val delta: Int = ViewConfiguration.get(getContext()).scaledTouchSlop

    override fun onTouchEvent(e: MotionEvent?): Boolean {
        val onTouchEvent = super.onTouchEvent(e)
        when (e?.action) {
            MotionEvent.ACTION_DOWN -> {
                // saving initial touch location
                x = e.rawX.toInt()
                y = e.rawY.toInt()
                isValid = true
            }
            MotionEvent.ACTION_MOVE -> {
                if (Math.abs(e.rawX - x) > delta ||
                        Math.abs(e.rawY - y) > delta) {
                    // if a scroll happens - no longer consider this movement as valid
                    // this is needed for handling scroll on the inner part of `RecyclerView`                            
                    isValid = false
                }
            }
            MotionEvent.ACTION_UP -> {
                if (isValid && Math.abs(e.rawX - x) < delta &&
                        Math.abs(e.rawY - y) < delta &&
                        isInRightArea(e)) {
                    // 1. if the movement is still valid
                    // 2. we have actually performed a click                            
                    // 3. the click is in expected rectangle
                    // then perform click
                    performClick()
                }
            }
        }
        return onTouchEvent
    }

    // This is needed in order to handle the edge case, when a click listener 
    // would be fired when performing a click between the items of `RecyclerView`
    private fun isInRightArea(e: MotionEvent): Boolean {
        val r = Rect()
        getGlobalVisibleRect(r)
        r.left = paddingLeft
        r.top = r.top + paddingTop
        return !r.contains(e.rawX.toInt(), e.rawY.toInt())
    }

}

Result:



来源:https://stackoverflow.com/questions/46930625/recyclerview-listen-to-padding-click-events

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!