Android Recyclerview:侦听填充单击事件

Android Recyclerview:侦听填充单击事件,android,android-recyclerview,kotlin,android-custom-view,android-touch-event,Android,Android Recyclerview,Kotlin,Android Custom View,Android Touch Event,我有一个水平的RecyclerView,其中leftPadding=48dp,topPadding=24dp和cliptoppadding=false。它从左边的空白处开始,但是当用户滚动列表时,它的项目会被绘制在该空白处(以前是空白的)。顶部空间总是空的 此RecyclerView位于具有前台=selectableItemBackground的框架布局内 我的问题来自这样一个事实,RecyclerView消耗并忽略了左侧和顶部空间的接触,这意味着无论是连接到FrameLayout还是连接到R

我有一个水平的
RecyclerView
,其中
leftPadding=48dp
topPadding=24dp
cliptoppadding=false
。它从左边的空白处开始,但是当用户滚动列表时,它的项目会被绘制在该空白处(以前是空白的)。顶部空间总是空的

RecyclerView
位于具有
前台=selectableItemBackground
的框架布局内

我的问题来自这样一个事实,
RecyclerView
消耗并忽略了左侧和顶部空间的接触,这意味着无论是连接到
FrameLayout
还是连接到
RecyclerView
,都不会触发
OnClickListener

我已经在
RecyclerView
上尝试了
clickable=false
focusable=false
,但它不起作用

我要找的是:

  • 可滚动
    RecyclerView
  • 可单击
    RecyclerView
    项目
  • FrameLayout
    单击
    RecyclerView的
    空白时单击事件
  • (3)可点击的
    RecyclerView的
    空白
  • 编辑:我创建了一个简单的项目,显示了我正在谈论的问题:
    共有2个提交,第一个提交我尝试捕获对父视图的单击,第二个提交我尝试捕获对RecyclerView本身的单击。这两种方法都不起作用。

    您必须创建自定义的
    RecyclerView
    实现,在该实现中,您可以监听触摸事件,并根据这些事件执行过滤

    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())
        }
    
    }
    
    类MyRecyclerView@JVM重载构造函数(
    context:context,attrs:AttributeSet?=null,defStyleAttr:Int=0
    ):RecyclerView(上下文、属性、defStyleAttr){
    私有变量isValid=false
    私有变量x:Int=0
    私有变量y:Int=0
    //这将帮助我们了解该事件是否可以被视为触摸或滚动
    private val delta:Int=ViewConfiguration.get(getContext()).scaledTouchSlop
    覆盖事件(e:MotionEvent?):布尔值{
    val onTouchEvent=super.onTouchEvent(e)
    何时(e?行动){
    MotionEvent.ACTION\u向下->{
    //保存初始触摸位置
    x=e.rawX.toInt()
    y=e.rawY.toInt()
    isValid=true
    }
    MotionEvent.ACTION\u MOVE->{
    如果(数学abs(e.rawX-x)>delta||
    数学abs(e.rawY-y)>三角洲){
    //如果发生滚动-不再认为这个运动是有效的。
    //这是处理“RecyclerView”内部的滚动条所必需的
    isValid=false
    }
    }
    MotionEvent.ACTION\u UP->{
    如果(isValid&&Math.abs(e.rawX-x)
    结果:


    显示您的代码。您希望看到什么代码?在您的recyclerview适配器中,您必须放置一个全局单击列表器和项目单击列表器,确保您仅对项目执行此操作。发布更多详细信息的代码每个项目的视图都有自己的clickListener,而不是适配器(它不是视图,无法注册clickListener)。问题不在于项目的点击监听器,而在于点击没有在项目的范围外注册(他们的点击监听器没有权限)。这就是我告诉你的精心构造的问题,我很喜欢阅读它。它就像一个符咒。