101 lines
3.1 KiB
Markdown
101 lines
3.1 KiB
Markdown
# Modifier.zoomable()
|
|
|
|
A `Modifier` for handling pan & zoom gestures, designed to be shared across all your media composables so that your users can use the same familiar gestures throughout your app. It offers,
|
|
|
|
- Pinch to zoom and flings
|
|
- Double tap to zoom
|
|
- Single finger zoom (double tap and hold)
|
|
- Haptic feedback for over/under zoom
|
|
- Compatibility with nested scrolling
|
|
- Click listeners
|
|
|
|
### Installation
|
|
|
|
```groovy
|
|
implementation("me.saket.telephoto:zoomable:{{ versions.telephoto }}")
|
|
```
|
|
|
|
```kotlin hl_lines="4"
|
|
Box(
|
|
Modifier
|
|
.size(200.dp)
|
|
.zoomable(rememberZoomableState())
|
|
.background(
|
|
brush = Brush.linearGradient(listOf(Color.Cyan, Color.Blue)),
|
|
shape = RoundedCornerShape(4.dp)
|
|
)
|
|
)
|
|
```
|
|
|
|
While `Modifier.zoomable()` was primarily written with images & videos in mind, it can be used for anything such as text, canvas drawings, etc.
|
|
|
|
### Edge detection
|
|
|
|
|  |  |
|
|
|:--------------------------------------------------:|:-------------------------------------------------:|
|
|
| Without edge detection | With edge detection |
|
|
|
|
|
|
For preventing your content from over-zooming or over-panning, `Modifier.zoomable()` will use your content's layout size by default. This is good enough for composables that fill _every_ pixel of their drawing space.
|
|
|
|
For richer content such as an `Image()` whose _visual_ size may not always match its layout size, `Modifier.zoomable()` will need your assistance.
|
|
|
|
```kotlin hl_lines="5-7"
|
|
val state = rememberZoomableState()
|
|
val painter = resourcePainter(R.drawable.example)
|
|
|
|
LaunchedEffect(painter.intrinsicSize) {
|
|
state.setContentLocation(
|
|
ZoomableContentLocation.scaledInsideAndCenterAligned(painter.intrinsicSize)
|
|
)
|
|
}
|
|
|
|
Image(
|
|
modifier = Modifier
|
|
.fillMaxSize()
|
|
.background(Color.Orange)
|
|
.zoomable(state),
|
|
painter = painter,
|
|
contentDescription = …,
|
|
contentScale = ContentScale.Inside,
|
|
alignment = Alignment.Center,
|
|
)
|
|
```
|
|
|
|
### Click listeners
|
|
For detecting double taps, `Modifier.zoomable()` consumes all tap gestures making it incompatible with `Modifier.clickable()` and `Modifier.combinedClickable()`. As an alternative, its `onClick` and `onLongClick` parameters can be used.
|
|
|
|
```kotlin
|
|
Modifier.zoomable(
|
|
state = rememberZoomableState(),
|
|
onClick = { … },
|
|
onLongClick = { … },
|
|
)
|
|
```
|
|
|
|
### Applying gesture transformations
|
|
|
|
When pan & zoom gestures are received, `Modifier.zoomable()` automatically applies their resulting `scale` and `translation` onto your content using `Modifier.graphicsLayer()`.
|
|
|
|
This can be disabled if your content prefers applying the transformations in a bespoke manner.
|
|
|
|
```kotlin hl_lines="2 10-11"
|
|
val state = rememberZoomableState(
|
|
autoApplyTransformations = false
|
|
)
|
|
|
|
Text(
|
|
modifier = Modifier
|
|
.fillMaxSize()
|
|
.zoomable(state),
|
|
text = "Nicolas Cage",
|
|
style = state.contentTransformation.let {
|
|
val weightMultiplier = if (it.isUnspecified) 1f else it.scale.scaleX
|
|
TextStyle(
|
|
fontSize = 36.sp,
|
|
fontWeight = FontWeight(400 * weightMultiplier),
|
|
)
|
|
}
|
|
)
|
|
```
|