是否可以阻止 Jetpack Compose 输入修饰符消耗输入事件?

Joh*_*ohn 12 android kotlin android-jetpack android-jetpack-compose

在旧的 Android 视图范例中,视图可以侦听 MotionEvent,而不消耗它们。DispatchTouchEvent或者OnTouchEvent可以简单地返回“false”,并且 MotionEvent 将穿过一层又一层的视图,直到返回“true”,此时 MotionEvent 被消耗并且永远不会传递到较低级别的视图。

如何在 Jetpack Compose (JC) 中做到这一点?

JC 触摸监听器Modifier.pointerInteropFilter消耗它检测到的每个 MotionEvent,并且无论它返回“true”还是“false”,都不会向下传递 MotionEvent。(这对我来说感觉像是一个错误,但这是我们必须处理的问题。)

当 JC 侦听器检测到一系列与他们正在查找的事件相匹配的事件时,它们都会消耗其输入事件Modifier.pointerInput.detectDragGesturesModifier.pointerInput.detectTapGestures

例如,这使得很难(但肯定不是不可能?)有条件地使用由笔创建的输入事件,但如果是由笔创建的,则将该事件传递到下一个可组合项(甚至是同一可组合项中的下一个侦听器)通过一根手指。

同样的问题在这里被问到,在狭义上,但它从未得到回答,OP 似乎仍然在努力解决这个限制。

我能想到解决此错误/限制的唯一方法是将 MotionEvent 手动传递到其他可组合项。

在旧的视图范例中,您可以手动定位视图的onTouchEvent方法,并将 MotionEvent 直接传递给该视图进行处理。这很好,因为例如,您可以有条件地将手指触摸传递到 View,然后 View 会处理自己的滚动,但拦截所有笔触摸并使用它们进行绘制而不是滚动。

但是,到底如何将输入事件直接传递给位于另一个可组合项下方的可组合项呢?或者,假设我必须在一个巨大的可组合项中而不是在可组合项的层中完成所有这些操作,那么如何在可组合项传递触摸事件呢?

我对这两种解决方案都很满意:首先不消耗输入事件/MotionEvents,然后让它们传递下去,直到有人需要它们为止;或手动传递它们。

但我也不知道该怎么做!

我也会对一个答案感到满意,告诉我我错误地将视图风格的思维引入可组合项,但是当涉及到有条件地使用输入事件和修饰符时,您能否概述一下我应该如何思考(在示例中我pointerInput)一直在使用)要么在可组合项上绘制,要么滚动它?

是否有相当于 Python 的 super() 功能,您可以在其中检测(例如)拖动手势,如果是手指拖动,则执行可组合项的默认操作(即滚动)?

Irf*_*tif 1

截至androidx.compose.ui:ui:1.4.3,如果我们从回来,则向下Modifier.pointerInteropFilter()传递。MotionEventfalseonTouchEvent()

Column {
  val msg = remember { mutableStateOf("") }

  Box(
      Modifier.fillMaxWidth().height(200.dp).padding(12.dp).background(Color.Cyan).clickable {
        msg.value += "Bottom Layout received a click\n"
      },
      contentAlignment = Alignment.Center) {
        Box(Modifier.fillMaxSize().padding(4.dp), contentAlignment = Alignment.TopStart) {
          Text("Bottom Layout")
        }

        Box(
            Modifier.fillMaxSize(0.6f).background(Color.Green).pointerInteropFilter {
              msg.value +=
                  "Top Layout received ${
                        when (it.action) {
                            0 -> "a down"
                            1 -> "an up"
                            else -> "a"
                        }
                    } touch event\n"

              // Must return false here to pass the event to bottom layout
              false
            },
            contentAlignment = Alignment.Center) {
              Text("Top Layout")
            }
      }

  Text(msg.value, Modifier.padding(12.dp))
}
Run Code Online (Sandbox Code Playgroud)

结果:

什么时候true返回:

什么时候false返回:

我用同样的方法来控制 的位置DropDownMenu