Recipes
Observing pan & zoom¶
val state = rememberZoomableState()
Box(
Modifier.zoomable(state)
)
LaunchedEffect(state.contentTransformation) {
println("Pan = ${state.contentTransformation.offset}")
println("Zoom = ${state.contentTransformation.scale}")
println("Zoom fraction = ${state.zoomFraction}")
}
// Example use case: Hide system bars when image is zoomed in.
val systemUi = rememberSystemUiController()
val isZoomedOut = (zoomState.zoomFraction ?: 0f) < 0.1f
LaunchedEffect(isZoomedOut) {
systemUi.isSystemBarsVisible = isZoomedOut
}
Controlling pan & zoom¶
val state = rememberZoomableState()
Box(
Modifier.zoomable(state)
)
Button(onClick = { state.zoomBy(zoomFactor = 1.2f) }) {
Text("+")
}
Button(onClick = { state.zoomBy(zoomFactor = 1 / 1.2f) }) {
Text("-")
}
Button(onClick = { state.panBy(offset = 50.dp) }) {
Text(">")
}
Button(onClick = { state.panBy(offset = -50.dp) }) {
Text("<")
}
Resetting zoom¶
Modifier.zoomable() will automatically retain its pan & zoom across state restorations. You may want to prevent this in lazy layouts such as a Pager(), where each page is restored every time it becomes visible.
val pagerState = rememberPagerState()
HorizontalPager(
state = pagerState,
pageCount = 3,
) { pageNum ->
val zoomableState = rememberZoomableState()
ZoomableContent(
state = zoomableState
)
if (pagerState.settledPage != pageNum) {
// Page is now off-screen. Prevent restoration of
// current zoom when this page becomes visible again.
LaunchedEffect(Unit) {
zoomableState.resetZoom(animationSpec = SnapSpec())
}
}
}
Warning
A bug in Pager() previously caused settledPage to reset to 0 upon state restoration. This issue has been resolved in androidx.compose.foundation:foundation:1.5.0-alpha02.
Observing press gestures¶
Modifier.zoomable() can emit press interactions to a MutableInteractionSource, useful for responding to hold gestures. For example, switching between two images for comparison on long press, or increasing video playback speed while pressed.
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
Box(
Modifier.zoomable(
state = rememberZoomableState(),
interactionSource = interactionSource,
)
) {
if (isPressed) {
// Show alternate content while pressed. For example,
// display a "before" image for comparison or increase
// video playback speed.
}
}