我目前正在try 实现一个选项,即在可zoom 、可平移(拖动曲面)或两者都不可用的可组合对象之间切换.到目前为止,有效的方法是切换相应的按钮,得到预期的结果.不起作用的是切换一个按钮和另一个按钮-这会产生意外的结果,即保持第一个按钮的功能.

  Modifier.run {
            if (zoomEnabled) {
                this.pointerInput(Unit) {
                    detectTransformGestures { _, _, zoom, _ ->
                        passScale(zoom)
                    }
                }
            } else if (panEnabled) {
                this.pointerInput(Unit) {
                    detectDragGestures { change, dragAmount ->
                        change.consumeAllChanges()
                        passOffsetX(dragAmount.x / 3)    
                        passOffsetY(dragAmount.y / 3)    
                    }   
                }
            } else
                this
        }

按钮:

@Composable
fun TopBarAction(
    zoomEnabled: Boolean,
    passZoomEnabled: (Boolean) -> Unit,
    panEnabled: Boolean,
    passPanEnabled: (Boolean) -> Unit
) {
    IconToggleButton(
        checked = zoomEnabled,
        onCheckedChange = {
            passPanEnabled(false)
            passZoomEnabled(it)
        },
        modifier = Modifier
            .background(
                if (zoomEnabled) Color.LightGray else Color.Transparent,
                shape = CircleShape
            ),
        enabled = true
    ) {
        Icon(...)
    }
    IconToggleButton(
        checked = panEnabled,
        onCheckedChange = {
            passZoomEnabled(false)
            passPanEnabled(it)
        },
        modifier = Modifier
            .background(
                if (panEnabled) Color.LightGray else Color.Transparent,
                shape = CircleShape
            ),
        enabled = true
    ) {
        Icon(...)
    }
}

使用法线.带有内部条件而不是运行的pointerInput修饰符根本无法识别任何输入,detectTransformGesture的pan没有按我需要的方式运行(尽管如果其他所有操作都失败,我可能会使用这一方法)

推荐答案

第一个问题是PointerInput使用一个或多个键创建闭包,并使用旧值,除非您设置的键发生更改.

您需要相应地设置关键点.

第二个问题是,即使您设置了键,DetectDragSignals或DetectTransferMgestures也会消耗事件,所以如果第一个指针已经消耗了事件,上面的PointerInputChange也不会得到它.

consume()consumeAllChanges()的作用是通过返回PointeInputChange.positionChange()Offset.ZeroPointerInputChange.isConsumedtrue来防止指针输入在其上方或父 node 上接收事件.因为拖动、滚动或变换手势会判断点输入是否发生变化.isConsumed是真的,如果您在前面的pointerInput中使用它们,它们将永远不会得到任何事件.

拖动实例的源代码

suspend fun PointerInputScope.detectDragGestures(
    onDragStart: (Offset) -> Unit = { },
    onDragEnd: () -> Unit = { },
    onDragCancel: () -> Unit = { },
    onDrag: (change: PointerInputChange, dragAmount: Offset) -> Unit
) {
    forEachGesture {
        awaitPointerEventScope {
            val down = awaitFirstDown(requireUnconsumed = false)
            var drag: PointerInputChange?
            var overSlop = Offset.Zero
            do {
                drag = awaitPointerSlopOrCancellation(
                    down.id,
                    down.type
                ) { change, over ->
                    change.consume()
                    overSlop = over
                }
            // ! EVERY Default GESTURE HAS THIS CHECK
            } while (drag != null && !drag.isConsumed)
            if (drag != null) {
                onDragStart.invoke(drag.position)
                onDrag(drag, overSlop)
                if (
                    !drag(drag.id) {
                        onDrag(it, it.positionChange())
                        it.consume()
                    }
                ) {
                    onDragCancel()
                } else {
                    onDragEnd()
                }
            }
        }
    }
}

而不是使用修饰语.运行"您可以链"修改器.指针输入()

Modifier
  .pointerInput(keys){
    // Gesture scope1
    if(zoomEnabled){...}
  } 
  .pointerInput(keys){
    // Gesture scope2
      if(panEnabled){
        ....
    }

  } 

事件首先转到手势范围2,然后转到手势范围1

创建了一个小示例,您可以观察手势如何更改和传播,以及如何使用按键重置

@Composable
private fun MyComposable() {

    var zoomEnabled by remember { mutableStateOf(false) }
    var dragEnabled by remember { mutableStateOf(false) }
    var text by remember { mutableStateOf("") }

    Column() {
        val modifier = Modifier
            .size(400.dp)
            .background(Color.Red)
            .pointerInput(zoomEnabled) {
              if (zoomEnabled) {
                  detectTransformGestures { centroid, pan, zoom, rotation ->
                      println("ZOOOMING")
                      text = "ZOOMING centroid: $centroid"
                  }
              }
            }
            .pointerInput(key1 = dragEnabled, key2= zoomEnabled) {
                if (dragEnabled && !zoomEnabled) {
                    detectDragGestures { change, dragAmount ->
                        println("DRAGGING")
                        text = "DRAGGING $dragAmount"
                    }
                }
            }
        Box(modifier = modifier)

        Text(text = text)

        OutlinedButton(onClick = { zoomEnabled = !zoomEnabled }) {
            Text("zoomEnabled: $zoomEnabled")
        }

        OutlinedButton(onClick = { dragEnabled = !dragEnabled }) {
            Text("dragEnabled: $dragEnabled")
        }
    }
}

您可以使用上面的答案和代码片段创建自己的行为.

Kotlin相关问答推荐

带有Spring Boot和Kotline的可嵌入实体

Kotlin编译器如何决定是否可以在任何给定点调用Suspend方法?

Kotlin stlib中是否有用于将列表<;对<;A,B&>;转换为对<;列表<;A&>,列表<;B&>;的函数

Kotlin 中的 maxOf() 和 max() 方法有什么区别?

Kotlin 启动与启动(Dispatchers.Default)

如何在 Kotlin 中为变量分配另一个变量的值?

Kotlin:如何使用第一个参数的默认值进行函数调用并为第二个参数传递一个值?

如何使用 Android CameraX 自动对焦

jetpack compose 将参数传递给 viewModel

Kotlin 解构超过五个组件

如何退出 Kotlinc 命令行编译器

Kotlin-通过与属性列表进行比较来筛选对象列表

Android 上的 Kotlin:将map到list

用Gradle Kotlin DSL构建源jar?

Java Integer.MAX_VALUE 与 Kotlin Int.MAX_VALUE

Kotlin lambda 语法混淆

如何启用spring security kotlin DSL?

将字符串转换为HashMap的最简单方法

带有注释为@RegisterExtension的字段的 JUnit 5 测试在 Kotlin 中不起作用

Kotlin for assertThat(foo, instanceOf(Bar.class))