Fix image zoom focal point
This commit is contained in:
1 parent
62cb6c91d5
commit
0b4da64062
2 files changed
+67
-5
No files matched your search
@@ -23,6 +23,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.FilterQuality
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
@@ -242,17 +243,28 @@ private fun ZoomableImage(image: ImageBitmap) {
|
||||
modifier =
|
||||
Modifier.fillMaxSize()
|
||||
.pointerInput(Unit) {
|
||||
detectTransformGestures { _, pan, zoom, _ ->
|
||||
detectTransformGestures { centroid, pan, zoom, _ ->
|
||||
// Floor of 1 so the image cannot be pinched smaller than fitted, which is
|
||||
// already the whole of it; a ceiling so it cannot be lost off-screen.
|
||||
scale = (scale * zoom).coerceIn(1f, 8f)
|
||||
if (scale > 1f) {
|
||||
offsetX += pan.x
|
||||
offsetY += pan.y
|
||||
val oldScale = scale
|
||||
val newScale = (oldScale * zoom).coerceIn(1f, 8f)
|
||||
if (newScale > 1f) {
|
||||
val offset =
|
||||
zoomOffset(
|
||||
Offset(offsetX, offsetY),
|
||||
centroid,
|
||||
pan,
|
||||
oldScale,
|
||||
newScale,
|
||||
Offset(size.width / 2f, size.height / 2f),
|
||||
)
|
||||
offsetX = offset.x
|
||||
offsetY = offset.y
|
||||
} else {
|
||||
offsetX = 0f
|
||||
offsetY = 0f
|
||||
}
|
||||
scale = newScale
|
||||
}
|
||||
}
|
||||
.graphicsLayer {
|
||||
@@ -263,3 +275,16 @@ private fun ZoomableImage(image: ImageBitmap) {
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/** Keeps the image point beneath [centroid] beneath the fingers as its scale changes. */
|
||||
internal fun zoomOffset(
|
||||
offset: Offset,
|
||||
centroid: Offset,
|
||||
pan: Offset,
|
||||
oldScale: Float,
|
||||
newScale: Float,
|
||||
viewportCenter: Offset,
|
||||
): Offset {
|
||||
val scaleChange = newScale / oldScale
|
||||
return offset * scaleChange + (centroid - viewportCenter) * (1f - scaleChange) + pan
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.example.aiapp
|
||||
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class SessionImageTest {
|
||||
@Test
|
||||
fun `zoom keeps the region panned to in the center`() {
|
||||
assertEquals(
|
||||
Offset(240f, -160f),
|
||||
zoomOffset(
|
||||
offset = Offset(120f, -80f),
|
||||
centroid = Offset(500f, 1000f),
|
||||
pan = Offset.Zero,
|
||||
oldScale = 2f,
|
||||
newScale = 4f,
|
||||
viewportCenter = Offset(500f, 1000f),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `zoom keeps an off-center pinch beneath moving fingers`() {
|
||||
assertEquals(
|
||||
Offset(460f, 420f),
|
||||
zoomOffset(
|
||||
offset = Offset(100f, -100f),
|
||||
centroid = Offset(250f, 400f),
|
||||
pan = Offset(10f, 20f),
|
||||
oldScale = 2f,
|
||||
newScale = 4f,
|
||||
viewportCenter = Offset(500f, 1000f),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user