android - 回收站查看 : listen to padding click events

标签 android android-recyclerview kotlin android-custom-view android-touch-event

我有一个带有 leftPadding = 48dptopPadding = 24dpclipToPadding = false 的水平 RecyclerView。它从左侧的空白区域开始,但是当用户滚动列表时,它的项目被绘制在那个(以前是空白的)空间上。顶部空间始终为空。

enter image description here

这个 RecyclerView 在 FrameLayout 中,foreground = selectableItemBackground

我的问题来自 RecyclerView 消耗并忽略左侧和顶部空间的触摸,这意味着 OnClickListener 不会被触发,无论是附加到FrameLayoutRecyclerView

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

我在寻找什么:

  1. 可滚动的RecyclerView enter image description here
  2. 可点击的RecyclerViewenter image description here
  3. FrameLayout点击RecyclerView的空白处时的点击事件
  4. (替代3)可点击的RecyclerView的空格 enter image description here enter image description here

编辑:我创建了一个简单的项目来显示我正在谈论的问题:https://github.com/dadino/recyclerviewemptyspacestest 有 2 次提交,第一次我 try catch 对父 View 的点击,第二次我 try catch 对 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())
    }

}

结果:

enter image description here

关于android - 回收站查看 : listen to padding click events,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46930625/

相关文章:

java - 你如何链接多个可观察对象?

java - RecyclerView 内的分组开关

gradle - 如何从 Gradle 中运行 Kotlin-Script (*.kts) 文件?

android - IntentService 的依赖注入(inject)不起作用

java - Android setContentView 与 Textview

java - 如何在我的应用程序中添加另一种语言?

android - 在 Android 的 RecyclerView 中检测动画完成

kotlin - Android Studio:Gradle同步失败:无法下载修补程序

java - ImageView 不显示

android - 从 View 模型类中获取 Activity 的上下文