gpt4 book ai didi

android - Jetpack compose 中更好的缩放行为

转载 作者:行者123 更新时间:2023-12-04 23:53:56 25 4
gpt4 key购买 nike

默认缩放行为 as explained in the compose documentation干扰 dragGestures 并围绕可缩放的中心而不是您的手指旋转和缩放
有一个更好的方法吗?

最佳答案

我将此解决方案中的代码放入库中:de.mr-pine.utils:zoomables
您必须使用 pointerInputScope with detectTransformGestures并将此功能作为您的 onGesture:

fun onTransformGesture(
centroid: Offset,
pan: Offset,
zoom: Float,
transformRotation: Float
) {
offset += pan
scale *= zoom
rotation += transformRotation

val x0 = centroid.x - imageCenter.x
val y0 = centroid.y - imageCenter.y

val hyp0 = sqrt(x0 * x0 + y0 * y0)
val hyp1 = zoom * hyp0 * (if (x0 > 0) {
1f
} else {
-1f
})

val alpha0 = atan(y0 / x0)

val alpha1 = alpha0 + (transformRotation * ((2 * PI) / 360))

val x1 = cos(alpha1) * hyp1
val y1 = sin(alpha1) * hyp1

transformOffset =
centroid - (imageCenter - offset) - Offset(x1.toFloat(), y1.toFloat())
offset = transformOffset
}
这是一个如何围绕触摸输入旋转/缩放的示例,它还支持滑动和双击以重置缩放/放大:
val scope = rememberCoroutineScope()

var scale by remember { mutableStateOf(1f) }
var rotation by remember { mutableStateOf(0f) }
var offset by remember { mutableStateOf(Offset.Zero) }
val state = rememberTransformableState { zoomChange, offsetChange, rotationChange ->
scale *= zoomChange
rotation += rotationChange
offset += offsetChange
}

var dragOffset by remember { mutableStateOf(Offset.Zero) }
var imageCenter by remember { mutableStateOf(Offset.Zero) }
var transformOffset by remember { mutableStateOf(Offset.Zero) }


Box(
Modifier
.pointerInput(Unit) {
detectTapGestures(
onDoubleTap = {
if (scale != 1f) {
scope.launch {
state.animateZoomBy(1 / scale)
}
offset = Offset.Zero
rotation = 0f
} else {
scope.launch {
state.animateZoomBy(2f)
}
}
}
)
}
.pointerInput(Unit) {
val panZoomLock = true
forEachGesture {
awaitPointerEventScope {
var transformRotation = 0f
var zoom = 1f
var pan = Offset.Zero
var pastTouchSlop = false
val touchSlop = viewConfiguration.touchSlop
var lockedToPanZoom = false
var drag: PointerInputChange?
var overSlop = Offset.Zero

val down = awaitFirstDown(requireUnconsumed = false)


var transformEventCounter = 0
do {
val event = awaitPointerEvent()
val canceled = event.changes.fastAny { it.positionChangeConsumed() }
var relevant = true
if (event.changes.size > 1) {
if (!canceled) {
val zoomChange = event.calculateZoom()
val rotationChange = event.calculateRotation()
val panChange = event.calculatePan()

if (!pastTouchSlop) {
zoom *= zoomChange
transformRotation += rotationChange
pan += panChange

val centroidSize =
event.calculateCentroidSize(useCurrent = false)
val zoomMotion = abs(1 - zoom) * centroidSize
val rotationMotion =
abs(transformRotation * PI.toFloat() * centroidSize / 180f)
val panMotion = pan.getDistance()

if (zoomMotion > touchSlop ||
rotationMotion > touchSlop ||
panMotion > touchSlop
) {
pastTouchSlop = true
lockedToPanZoom =
panZoomLock && rotationMotion < touchSlop
}
}

if (pastTouchSlop) {
val eventCentroid = event.calculateCentroid(useCurrent = false)
val effectiveRotation =
if (lockedToPanZoom) 0f else rotationChange
if (effectiveRotation != 0f ||
zoomChange != 1f ||
panChange != Offset.Zero
) {
onTransformGesture(
eventCentroid,
panChange,
zoomChange,
effectiveRotation
)
}
event.changes.fastForEach {
if (it.positionChanged()) {
it.consumeAllChanges()
}
}
}
}
} else if (transformEventCounter > 3) relevant = false
transformEventCounter++
} while (!canceled && event.changes.fastAny { it.pressed } && relevant)

do {
val event = awaitPointerEvent()
drag = awaitTouchSlopOrCancellation(down.id) { change, over ->
change.consumePositionChange()
overSlop = over
}
} while (drag != null && !drag.positionChangeConsumed())
if (drag != null) {
dragOffset = Offset.Zero
if (scale !in 0.92f..1.08f) {
offset += overSlop
} else {
dragOffset += overSlop
}
if (drag(drag.id) {
if (scale !in 0.92f..1.08f) {
offset += it.positionChange()
} else {
dragOffset += it.positionChange()
}
it.consumePositionChange()
}
) {
if (scale in 0.92f..1.08f) {
val offsetX = dragOffset.x
if (offsetX > 300) {
onSwipeRight()

} else if (offsetX < -300) {
onSwipeLeft()
}
}
}
}
}
}
}
) {
ZoomComposable(
modifier = Modifier
.offset { IntOffset(offset.x.roundToInt(), offset.y.roundToInt()) }
.graphicsLayer(
scaleX = scale - 0.02f,
scaleY = scale - 0.02f,
rotationZ = rotation
)
.onGloballyPositioned { coordinates ->
val localOffset =
Offset(
coordinates.size.width.toFloat() / 2,
coordinates.size.height.toFloat() / 2
)
val windowOffset = coordinates.localToWindow(localOffset)
imageCenter = coordinates.parentLayoutCoordinates?.windowToLocal(windowOffset)
?: Offset.Zero
}
)
}

关于android - Jetpack compose 中更好的缩放行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69782529/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com