Skip to content

Instantly share code, notes, and snippets.

@alashow
Created July 3, 2021 03:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alashow/6492f6407434ca42ad7819dde2ae4a8e to your computer and use it in GitHub Desktop.
Save alashow/6492f6407434ca42ad7819dde2ae4a8e to your computer and use it in GitHub Desktop.
/*
* Copyright (C) 2021, Alashov Berkeli
* All rights reserved.
*/
package tm.alashow.common.compose.ui
import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.gestures.detectTransformGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
/**
* Makes given [content] zoomable, optionally snaps back when [snapBack] is true.
*/
@Composable
fun Zoomable(
maxScale: Float = 4f,
minScale: Float = 0.7f,
snapBack: Boolean = true,
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
val coroutineScope = rememberCoroutineScope()
val scale = remember { Animatable(1f) }
val rotation = remember { Animatable(0f) }
val panX = remember { Animatable(0f) }
val panY = remember { Animatable(0f) }
var snapBackJob: Job? = null
Box(
modifier = modifier
.pointerInput(Unit) {
detectTransformGestures(false) { _, pan, zoomChange, rotationChange ->
coroutineScope.launch {
scale.snapTo(zoomChange.coerceIn(minScale, maxScale))
rotation.snapTo(rotation.value + rotationChange)
panX.snapTo(panX.value + pan.x)
panY.snapTo(panY.value + pan.y)
if (snapBack) {
snapBackJob?.cancel()
snapBackJob = launch {
delay(150)
launch { scale.animateTo(1f) }
launch { rotation.animateTo(0f) }
launch { panX.animateTo(0f) }
launch { panY.animateTo(0f) }
}
}
}
}
}
.graphicsLayer(
scaleX = scale.value,
scaleY = scale.value,
translationX = panX.value,
translationY = panY.value,
rotationZ = rotation.value
)
) {
content()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment