使用Jetpack Compose完成自定义手势处理,深度解析,值得收藏

本文详细介绍了如何在Jetpack Compose中使用detectTransformGestures、forEachGesture等API进行自定义手势处理。通过示例展示了拖动、缩放与旋转手势的实现,以及如何进行事件分发和消费,帮助开发者更好地理解和利用Jetpack Compose进行手势操作。同时,文章提到了awaitPointerEvent、awaitFirstDown等基础手势方法,以及awaitDragOrCancellation的用法,强调了它们在手势处理中的角色和区别。
摘要由CSDN通过智能技术生成

)

}

}

变换类型基础 API

API 介绍

| API名称 | 作用 |

| — | — |

| detectTransformGestures | 监听拖动、缩放与旋转手势 |

Transfomer Modifier 不同的是,通过这个 API 可以监听单指的拖动手势,和拖动类型基础 API所提供的功能一样,除此之外还支持监听双指缩放与旋转手势。反观Transfomer Modifier 只能监听到双指拖动手势,不知设计成这样的行为不一致是否是 Google 有意而为之。

举例说明

接下来我们为这个绿色方块添加变化手势处理逻辑。detectTransformGestures 方法提供了两个参数。

panZoomLock(可选): 当拖动或缩放手势发生时是否支持旋转

onGesture(必须):当拖动、缩放或旋转手势发生时回调

suspend fun PointerInputScope.detectTransformGestures(

panZoomLock: Boolean = false,

onGesture: (centroid: Offset, pan: Offset, zoom: Float, rotation: Float) -> Unit

)

💡 Tips

关于偏移、缩放与旋转,我们建议的调用顺序是 rotate -> scale -> offset

  1. 若offset发生在rotate之前时,rotate会对offset造成影响。具体表现为当出现拖动手势时,组件会以当前角度为坐标轴进行偏移。
  1. 若offset发生在scale之前是,scale也会对offset造成影响。具体表现为UI组件在拖动时不跟手

@Preview

@Composable

fun TransformGestureDemo() {

var boxSize = 100.dp

var offset by remember { mutableStateOf(Offset.Zero) }

var ratationAngle by remember { mutableStateOf(0f) }

var scale by remember { mutableStateOf(1f) }

Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {

Box(Modifier

.size(boxSize)

.rotate(ratationAngle) // 需要注意offset与rotate的调用先后顺序

.scale(scale)

.offset {

IntOffset(offset.x.roundToInt(), offset.y.roundToInt())

}

.background(Color.Green)

.pointerInput(Unit) {

detectTransformGestures(

panZoomLock = true, // 平移或放大时是否可以旋转

onGesture = { centroid: Offset, pan: Offset, zoom: Float, rotation: Float ->

offset += pan

scale *= zoom

ratationAngle += rotation

}

)

}

)

}

}

transform

forEachGesture

在传统 View 系统中,一次手指按下、移动到抬起过程中的所有手势事件可以共同构成一个手势事件序列。我们可以通过自定义手势处理来对于每一个手势事件序列进行定制处理。Compose 提供了 forEachGesture 以允许用户可以对每一个手势事件序列进行相同的定制处理。如果我们忘记使用 forEachGesture ,那么只会处理第一次手势事件序列。有些同学可能会问,为什么我不能在手势处理逻辑最外层套一层 while(true) 呢,通过 forEachGesture 的实现我们可以看到 forEachGesture 其实内部也是由while 实现的,除此之外他保证了协程只有存活时才能监听手势事件,同时也保证了每次交互结束时所有手指都是离开屏幕的。有些同学看到 while 可能新生疑问,难道这样不会阻塞主线程嘛?其实我们在介绍 PointerInput Modifier 时就提到过,我们的手势操作处理均发生在协程中。其实前面我们所提到的绝大多数 API 其内部实现均使用了 forEachGesture 。有些特殊场景下我们仅使用前面所提出的 API 可能仍然无法满足我们的需求,当然如果可以满足的话我们直接使用其分别对应的 Modifier 即可,前面所提出的 API 存在的意义是为了方便开发者为其进行功能拓展。既然要掌握自定义手势处理,我们就要从更底层角度来看这些上层 API 是如何实现的,了解原理我们就可以轻松自定义了。

suspend fun PointerInputScope.forEachGesture(block: suspend PointerInputScope.() -> Unit) {

val currentContext = currentCoroutineContext()

while (currentContext.isActive) {

try {

block()

// 挂

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值