Skip to content

Commit 5ef9395

Browse files
use Modifier.zoom and zoomState with ZoomableImage
1 parent 5c57c87 commit 5ef9395

File tree

1 file changed

+42
-86
lines changed

1 file changed

+42
-86
lines changed

image/src/main/java/com/smarttoolfactory/image/zoom/ZoomableImage.kt

Lines changed: 42 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,16 @@
11
package com.smarttoolfactory.image.zoom
22

3-
import androidx.compose.animation.core.Animatable
4-
import androidx.compose.animation.core.VectorConverter
5-
import androidx.compose.animation.core.spring
63
import androidx.compose.foundation.Image
7-
import androidx.compose.foundation.gestures.detectTapGestures
8-
import androidx.compose.runtime.*
4+
import androidx.compose.runtime.Composable
95
import androidx.compose.ui.Alignment
106
import androidx.compose.ui.Modifier
11-
import androidx.compose.ui.draw.clipToBounds
12-
import androidx.compose.ui.geometry.Offset
13-
import androidx.compose.ui.geometry.Size
14-
import androidx.compose.ui.graphics.*
7+
import androidx.compose.ui.graphics.ColorFilter
8+
import androidx.compose.ui.graphics.DefaultAlpha
9+
import androidx.compose.ui.graphics.FilterQuality
10+
import androidx.compose.ui.graphics.ImageBitmap
1511
import androidx.compose.ui.graphics.drawscope.DrawScope
16-
import androidx.compose.ui.input.pointer.pointerInput
1712
import androidx.compose.ui.layout.ContentScale
18-
import androidx.compose.ui.platform.LocalDensity
19-
import com.smarttoolfactory.gesture.detectTransformGestures
2013
import com.smarttoolfactory.image.ImageWithConstraints
21-
import kotlinx.coroutines.launch
2214

2315
/**
2416
* Zoomable image that zooms in and out in [ [minZoom], [maxZoom] ] interval and translates
@@ -30,6 +22,19 @@ import kotlinx.coroutines.launch
3022
* @param maxZoom maximum zoom value this Composable can possess
3123
* @param clipTransformToContentScale when set true zoomable image takes borders of image drawn
3224
* while zooming in. [contentScale] determines whether will be empty spaces on edges of Composable
25+
* @param limitPan limits pan to bounds of parent Composable. Using this flag prevents creating
26+
* empty space on sides or edges of parent.
27+
* @param consume flag to prevent other gestures such as scroll, drag or transform to get
28+
* event propagations
29+
* @param zoomEnabled when set to true zoom is enabled
30+
* @param panEnabled when set to true pan is enabled
31+
* @param rotationEnabled when set to true rotation is enabled
32+
* @param onGestureStart callback to to notify gesture has started and return current ZoomData
33+
* of this modifier
34+
* @param onGesture callback to notify about ongoing gesture and return current ZoomData
35+
* of this modifier
36+
* @param onGestureEnd callback to notify that gesture finished and return current ZoomData
37+
* of this modifier
3338
*/
3439
@Composable
3540
fun ZoomableImage(
@@ -42,79 +47,36 @@ fun ZoomableImage(
4247
initialZoom: Float = 1f,
4348
minZoom: Float = 1f,
4449
maxZoom: Float = 5f,
50+
limitPan: Boolean = true,
51+
zoomEnabled: Boolean = true,
52+
panEnabled: Boolean = true,
53+
rotationEnabled: Boolean = false,
54+
consume: Boolean = true,
55+
onGestureStart: (ZoomData) -> Unit = {},
56+
onGesture: (ZoomData) -> Unit = {},
57+
onGestureEnd: (ZoomData) -> Unit = {},
4558
clipTransformToContentScale: Boolean = false,
4659
colorFilter: ColorFilter? = null,
4760
filterQuality: FilterQuality = DrawScope.DefaultFilterQuality,
4861
) {
4962

50-
val coroutineScope = rememberCoroutineScope()
51-
val zoomMin = minZoom.coerceAtLeast(.5f)
52-
val zoomMax = maxZoom.coerceAtLeast(1f)
53-
val zoomInitial = initialZoom.coerceIn(zoomMin, zoomMax)
54-
55-
require(zoomMax >= zoomMin)
56-
57-
var size by remember { mutableStateOf(Size.Zero) }
58-
59-
val animatableOffset = remember(imageBitmap, contentScale) {
60-
Animatable(Offset.Zero, Offset.VectorConverter)
61-
}
62-
val animatableZoom = remember(imageBitmap, contentScale) { Animatable(zoomInitial) }
63-
6463
val zoomModifier = Modifier
65-
.clipToBounds()
66-
.graphicsLayer {
67-
val zoom = animatableZoom.value
68-
translationX = animatableOffset.value.x
69-
translationY = animatableOffset.value.y
70-
scaleX = zoom
71-
scaleY = zoom
72-
}
73-
.pointerInput(imageBitmap, contentScale) {
74-
75-
detectTransformGestures(
76-
onGesture = { _,
77-
gesturePan: Offset,
78-
gestureZoom: Float,
79-
_,
80-
_,
81-
_ ->
82-
83-
var zoom = animatableZoom.value
84-
val offset = animatableOffset.value
85-
86-
zoom = (zoom * gestureZoom).coerceIn(zoomMin, zoomMax)
87-
val newOffset = offset + gesturePan.times(zoom)
88-
89-
val maxX = (size.width * (zoom - 1) / 2f).coerceAtLeast(0f)
90-
val maxY = (size.height * (zoom - 1) / 2f).coerceAtLeast(0f)
91-
92-
coroutineScope.launch {
93-
animatableZoom.snapTo(zoom)
94-
}
95-
coroutineScope.launch {
96-
animatableOffset.snapTo(
97-
Offset(
98-
newOffset.x.coerceIn(-maxX, maxX),
99-
newOffset.y.coerceIn(-maxY, maxY)
100-
)
101-
)
102-
}
103-
}
104-
)
105-
}
106-
.pointerInput(imageBitmap, contentScale) {
107-
detectTapGestures(
108-
onDoubleTap = {
109-
coroutineScope.launch {
110-
animatableOffset.animateTo(Offset.Zero, spring())
111-
}
112-
coroutineScope.launch {
113-
animatableZoom.animateTo(zoomInitial, spring())
114-
}
115-
}
116-
)
117-
}
64+
.zoom(
65+
Unit,
66+
limitPan = limitPan,
67+
zoomEnabled = zoomEnabled,
68+
panEnabled = panEnabled,
69+
rotationEnabled = rotationEnabled,
70+
zoomState = rememberZoomState(
71+
initialZoom = initialZoom,
72+
minZoom = minZoom,
73+
maxZoom = maxZoom
74+
),
75+
consume = consume,
76+
onGestureStart = onGestureStart,
77+
onGesture = onGesture,
78+
onGestureEnd = onGestureEnd
79+
)
11880

11981
ImageWithConstraints(
12082
modifier = if (clipTransformToContentScale) modifier else modifier.then(zoomModifier),
@@ -128,12 +90,6 @@ fun ZoomableImage(
12890
drawImage = !clipTransformToContentScale
12991
) {
13092

131-
size = with(LocalDensity.current) {
132-
Size(
133-
width = imageWidth.toPx(),
134-
height = imageHeight.toPx()
135-
)
136-
}
13793

13894
if (clipTransformToContentScale) {
13995
Image(

0 commit comments

Comments
 (0)