Android Kotlin中,子元素的onClick事件会阻止父元素的OnTouch事件吗?

3

我有这样的布局层次结构:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/parent"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.xxxxxx.Widget
        android:id="@+id/widget1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <com.xxxxxx.Widget
        android:id="@+id/widget2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    </LinearLayout>
</LinearLayout>

我有一个 Parent LinearLayout 的触摸事件,如下:

parent.setOnTouchListener(myCustomTouchParent)

    class MyCustomTouchParent(ctx: Context): View.OnTouchListener {

        private var isScrollingDown = false
        private var isScrollingUp = false
        private val myGestureDetected = GestureDetector(ctx, MyGestureListener())

        var onRecyclerViewMovingDown: (() -> Unit)? = null

        override fun onTouch(p0: View?, e: MotionEvent): Boolean {
            myGestureDetected.onTouchEvent(e)

            when(e.action){
                MotionEvent.ACTION_UP -> {
                    if (isScrollingDown) {
                        onRecyclerViewMovingDown?.invoke()
                    }
                }

                MotionEvent.ACTION_DOWN -> {
                    Log.i("TAg", "Action Down")
                    isScrollingDown = false
                    isScrollingUp = false

                }
            }
            return true
        }

        inner class MyGestureListener: GestureDetector.SimpleOnGestureListener() {
            override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
                if(e2.y - e1.y > 0){
                    isScrollingUp = true
                } else if(e2.y - e1.y < 0){
                    isScrollingDown = true
                }
                return super.onScroll(e1, e2, distanceX, distanceY)
            }


        }
    }

基本上,这将检测父元素上的“向上滚动”事件,并执行一些动画。问题是,一旦我为widget1和widget2设置了点击监听器,父元素的触摸事件就不再起作用了。有没有解决方法?

除非你所使用的语言在其框架中有一些奇怪的东西,否则相反的情况应该是正确的-一个未正确编写并调用performClick的触摸处理程序不会调用点击处理程序。顺便说一句,你可能想要标记这个问题与你正在使用的语言/框架,因为这不是Java和Android SDK。 - Gabe Sechan
你能详细说明一下“相反的情况应该是真实的”吗? - johnny_crq
一个触摸处理程序需要调用performClick才能触发点击监听器。你的没有,所以它实际上永远不会调用点击监听器。默认的触摸监听器可以正确地执行此操作,但如果您覆盖它,则需要自己执行。这实际上非常重要-可访问性功能取决于点击发生,因此,如果您做得不对,将破坏屏幕阅读器和类似的可访问性应用程序。 - Gabe Sechan
非常好,谢谢。但问题不在那里。触摸监听器是为父级定义的,并且它运行良好。当我为子元素设置点击监听器时,触摸监听器停止工作。 - johnny_crq
2个回答

1
我唯一有效的解决方法是:在父级LinearLayout中拦截触摸事件,调用onTouchEvent并返回false:
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        onTouchEvent(ev)
        return false
    }

将Gesture Detector类中的TouchInterceptor移动到父onTouchEvent中:
override fun onTouchEvent(e: MotionEvent): Boolean {
            myGestureDetected.onTouchEvent(e)

            when(e.action){
                MotionEvent.ACTION_UP -> {
                    if (isScrollingDown) {
                        onRecyclerViewMovingDown?.invoke()
                    }
                }

                MotionEvent.ACTION_DOWN -> {
                    isScrollingDown = false
                    isScrollingUp = false

                }
            }
            return super.onTouchEvent(e)
        }

我不知道是否有更好的解决方案,但这个让我先处理父级触摸事件,然后将触摸传递给子元素。在那里,您可以设置单击监听器。
此外,如果您不设置单击监听器,则包含可点击项的触摸区域将不会触发触摸。因此最好设置。
clickable=true

在所有项目中设置监听器,只有在需要时才设置。

0

你需要重写子视图的onTouchListener并返回false,这样它们就不会覆盖父级ontouch了。

widget1.onTouch { view, motionEvent -> return@onTouch false }
widget2.onTouch { view, motionEvent -> return@onTouch false }

仍然无法正常工作。由于某种原因,如果我设置了点击监听器,则父级ACTION_DOWN被调用,但父级ACTION_UP未被调用。基本上,我想在调用单击监听器的同一区域内检测swipeUp。两者都不能正常工作,我正在寻找解决方法。尝试在子项OnInterceptTouchEvent中返回false。结果相同。 - johnny_crq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接