Skip to content

Commit 9d2c9e9

Browse files
authored
Merge pull request #9 from Mr-Pine/development
Merge for Version 1.1.2
2 parents 8540c33 + d5cd4ba commit 9d2c9e9

File tree

4 files changed

+60
-36
lines changed

4 files changed

+60
-36
lines changed

zoomables/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ dependencies {
5757

5858
ext{
5959
PUBLISH_GROUP_ID = 'de.mr-pine.utils'
60-
PUBLISH_VERSION = '1.1.1'
60+
PUBLISH_VERSION = '1.1.2'
6161
PUBLISH_ARTIFACT_ID = 'zoomables'
6262
}
6363

zoomables/src/main/kotlin/de/mr_pine/zoomables/ZoomableImage.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import kotlinx.coroutines.CoroutineScope
2323
* @param contentDescription text for accessibility see [Image] for further info
2424
* @param onSwipeLeft Optional function to run when user swipes from right to left - does nothing by default
2525
* @param onSwipeRight Optional function to run when user swipes from left to right - does nothing by default
26+
* @param dragGesturesEnabled A function with a [ZoomableState] scope that returns a boolean value to enable/disable dragging gestures (swiping and panning). Returns `true` by default. *Note*: For some use cases it may be required that only panning is possible. Use `{!notTransformed}` in that case
2627
* @param onDoubleTap Optional function to run when user double taps. Zooms in by 2x when scale is currently 1 and zooms out to scale = 1 when zoomed in when null (default)
2728
*/
2829
@Composable
@@ -34,13 +35,15 @@ public fun ZoomableImage(
3435
contentDescription: String? = null,
3536
onSwipeLeft: () -> Unit = {},
3637
onSwipeRight: () -> Unit = {},
38+
dragGesturesEnabled: ZoomableState.() -> Boolean = { true },
3739
onDoubleTap: ((Offset) -> Unit)? = null
3840
) {
3941
Zoomable(
4042
coroutineScope = coroutineScope,
4143
zoomableState = zoomableState,
4244
onSwipeLeft = onSwipeLeft,
4345
onSwipeRight = onSwipeRight,
46+
dragGesturesEnabled = dragGesturesEnabled,
4447
onDoubleTap = onDoubleTap
4548
) {
4649
Image(bitmap = bitmap, contentDescription = contentDescription, modifier = modifier)
@@ -57,6 +60,7 @@ public fun ZoomableImage(
5760
* @param contentDescription text for accessibility see [Image] for further info
5861
* @param onSwipeLeft Optional function to run when user swipes from right to left - does nothing by default
5962
* @param onSwipeRight Optional function to run when user swipes from left to right - does nothing by default
63+
* @param dragGesturesEnabled A function with a [ZoomableState] scope that returns a boolean value to enable/disable dragging gestures (swiping and panning). Returns `true` by default. *Note*: For some use cases it may be required that only panning is possible. Use `{!notTransformed}` in that case
6064
* @param onDoubleTap Optional function to run when user double taps. Zooms in by 2x when scale is currently 1 and zooms out to scale = 1 when zoomed in when null (default)
6165
*/
6266
@Composable
@@ -68,13 +72,15 @@ public fun ZoomableImage(
6872
contentDescription: String? = null,
6973
onSwipeLeft: () -> Unit = {},
7074
onSwipeRight: () -> Unit = {},
75+
dragGesturesEnabled: ZoomableState.() -> Boolean = { true },
7176
onDoubleTap: ((Offset) -> Unit)? = null
7277
) {
7378
Zoomable(
7479
coroutineScope = coroutineScope,
7580
zoomableState = zoomableState,
7681
onSwipeLeft = onSwipeLeft,
7782
onSwipeRight = onSwipeRight,
83+
dragGesturesEnabled = dragGesturesEnabled,
7884
onDoubleTap = onDoubleTap
7985
) {
8086
Image(
@@ -95,6 +101,7 @@ public fun ZoomableImage(
95101
* @param contentDescription text for accessibility see [Image] for further info
96102
* @param onSwipeLeft Optional function to run when user swipes from right to left - does nothing by default
97103
* @param onSwipeRight Optional function to run when user swipes from left to right - does nothing by default
104+
* @param dragGesturesEnabled A function with a [ZoomableState] scope that returns a boolean value to enable/disable dragging gestures (swiping and panning). Returns `true` by default. *Note*: For some use cases it may be required that only panning is possible. Use `{!notTransformed}` in that case
98105
* @param onDoubleTap Optional function to run when user double taps. Zooms in by 2x when scale is currently 1 and zooms out to scale = 1 when zoomed in when null (default)
99106
*/
100107
@Composable
@@ -106,13 +113,15 @@ public fun ZoomableImage(
106113
contentDescription: String? = null,
107114
onSwipeLeft: () -> Unit = {},
108115
onSwipeRight: () -> Unit = {},
116+
dragGesturesEnabled: ZoomableState.() -> Boolean = { true },
109117
onDoubleTap: ((Offset) -> Unit)? = null
110118
) {
111119
Zoomable(
112120
coroutineScope = coroutineScope,
113121
zoomableState = zoomableState,
114122
onSwipeLeft = onSwipeLeft,
115123
onSwipeRight = onSwipeRight,
124+
dragGesturesEnabled = dragGesturesEnabled,
116125
onDoubleTap = onDoubleTap
117126
) {
118127
Image(painter = painter, contentDescription = contentDescription, modifier = modifier)

zoomables/src/main/kotlin/de/mr_pine/zoomables/ZoomableState.kt

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ import kotlin.math.sqrt
2828
*
2929
* @param onTransformation callback invoked when transformation occurs. The callback receives the
3030
* change from the previous event. It's relative scale multiplier for zoom, [Offset] in pixels
31-
* for pan and degrees for rotation. If this parameter is null the default behaviour is
32-
* zooming, panning and rotating by the supplied changes. Rotation is kept between positive and negative 180
31+
* for pan and degrees for rotation.
3332
*
3433
* @property scale The current scale as [MutableState]<[Float]>
3534
* @property offset The current offset as [MutableState]<[Offset]>
3635
* @property rotation The current rotation in degrees as [MutableState]<[Float]>
36+
* @property notTransformed `true` if [scale] is `1`, [offset] is [Offset.Zero] and [rotation] is `0`
3737
*/
3838
public class ZoomableState(
3939
public var scale: MutableState<Float>,
@@ -42,6 +42,12 @@ public class ZoomableState(
4242
public val rotationBehavior: Rotation,
4343
onTransformation: ZoomableState.(zoomChange: Float, panChange: Offset, rotationChange: Float) -> Unit
4444
) : TransformableState {
45+
46+
public val notTransformed: Boolean
47+
get() {
48+
return scale.value in (1 - 1.0E-3f)..(1 + 1.0E-3f) && offset.value.getDistanceSquared() in -1.0E-6f..1.0E-6f && rotation.value in -1.0E-3f..1.0E-3f
49+
}
50+
4551
private val transformScope: TransformScope = object : TransformScope {
4652
override fun transformBy(zoomChange: Float, panChange: Offset, rotationChange: Float) =
4753
onTransformation(zoomChange, panChange, rotationChange)
@@ -51,6 +57,7 @@ public class ZoomableState(
5157

5258
private val isTransformingState = mutableStateOf(false)
5359

60+
5461
override suspend fun transform(
5562
transformPriority: MutatePriority,
5663
block: suspend TransformScope.() -> Unit
@@ -87,7 +94,11 @@ public class ZoomableState(
8794
}
8895
}
8996

90-
public suspend fun animateZoomToPosition(zoomChange: Float, position: Offset, currentComposableCenter: Offset = Offset.Zero) {
97+
public suspend fun animateZoomToPosition(
98+
zoomChange: Float,
99+
position: Offset,
100+
currentComposableCenter: Offset = Offset.Zero
101+
) {
91102
val offsetBuffer = offset.value
92103

93104
val x0 = position.x - currentComposableCenter.x
@@ -143,7 +154,7 @@ public class ZoomableState(
143154
*
144155
* @param onTransformation callback invoked when transformation occurs. The callback receives the
145156
* change from the previous event. It's relative scale multiplier for zoom, [Offset] in pixels
146-
* for pan and degrees for rotation. If this parameter is null the default behaviour is
157+
* for pan and degrees for rotation. If not provided the default behaviour is
147158
* zooming, panning and rotating by the supplied changes. Rotation is kept between positive and negative 180
148159
*
149160
* @return A [ZoomableState] initialized with the given [initialZoom], [initialOffset] and [initialRotation]

zoomables/src/main/kotlin/de/mr_pine/zoomables/Zoomables.kt

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,18 @@ import kotlin.math.*
3434
*
3535
* @param coroutineScope used for smooth asynchronous zoom/pan/rotation animations
3636
* @param zoomableState Contains the current transform states - obtained via [rememberZoomableState]
37+
* @param dragGesturesEnabled A function with a [ZoomableState] scope that returns a boolean value to enable/disable dragging gestures (swiping and panning). Returns `true` by default. *Note*: For some use cases it may be required that only panning is possible. Use `{!notTransformed}` in that case
3738
* @param onSwipeLeft Optional function to run when user swipes from right to left - does nothing by default
3839
* @param onSwipeRight Optional function to run when user swipes from left to right - does nothing by default
3940
* @param minimumSwipeDistance Minimum distance the user has to travel on the screen for it to count as swiping
40-
* @param onDoubleTap Optional function to run when user double taps. Zooms in by 2x to the touch point when scale is currently 1 and zooms out to scale = 1 when zoomed in when null (default)
41+
* @param onDoubleTap Optional function to run when user double taps. Zooms in by 2x to the touch point when scale is currently 1 and zooms out to scale = 1 when zoomed in when `null` (default)
4142
*/
4243

4344
@Composable
4445
public fun Zoomable(
4546
coroutineScope: CoroutineScope,
4647
zoomableState: ZoomableState,
48+
dragGesturesEnabled: ZoomableState.() -> Boolean = { true },
4749
onSwipeLeft: () -> Unit = {},
4850
onSwipeRight: () -> Unit = {},
4951
minimumSwipeDistance: Int = 0,
@@ -198,40 +200,42 @@ public fun Zoomable(
198200
transformEventCounter++
199201
} while (!canceled && event.changes.fastAny { it.pressed } && relevant)
200202

201-
do {
202-
awaitPointerEvent()
203-
drag = awaitTouchSlopOrCancellation(down.id) { change, over ->
204-
change.consumePositionChange()
205-
overSlop = over
206-
}
207-
} while (drag != null && !drag.positionChangeConsumed())
208-
if (drag != null) {
209-
dragOffset = Offset.Zero
210-
if (zoomableState.scale.value !in 0.92f..1.08f) {
211-
coroutineScope.launch {
212-
zoomableState.transform {
213-
transformBy(1f, overSlop, 0f)
214-
}
203+
if (zoomableState.dragGesturesEnabled()) {
204+
do {
205+
awaitPointerEvent()
206+
drag = awaitTouchSlopOrCancellation(down.id) { change, over ->
207+
change.consumePositionChange()
208+
overSlop = over
215209
}
216-
} else {
217-
dragOffset += overSlop
218-
}
219-
if (drag(drag.id) {
220-
if (zoomableState.scale.value !in 0.92f..1.08f) {
221-
zoomableState.offset.value += it.positionChange()
222-
} else {
223-
dragOffset += it.positionChange()
210+
} while (drag != null && !drag.positionChangeConsumed())
211+
if (drag != null) {
212+
dragOffset = Offset.Zero
213+
if (zoomableState.scale.value !in 0.92f..1.08f) {
214+
coroutineScope.launch {
215+
zoomableState.transform {
216+
transformBy(1f, overSlop, 0f)
217+
}
224218
}
225-
it.consumePositionChange()
219+
} else {
220+
dragOffset += overSlop
226221
}
227-
) {
228-
if (zoomableState.scale.value in 0.92f..1.08f) {
229-
val offsetX = dragOffset.x
230-
if (offsetX > minimumSwipeDistance) {
231-
onSwipeRight()
222+
if (drag(drag.id) {
223+
if (zoomableState.scale.value !in 0.92f..1.08f) {
224+
zoomableState.offset.value += it.positionChange()
225+
} else {
226+
dragOffset += it.positionChange()
227+
}
228+
it.consumePositionChange()
229+
}
230+
) {
231+
if (zoomableState.scale.value in 0.92f..1.08f) {
232+
val offsetX = dragOffset.x
233+
if (offsetX > minimumSwipeDistance) {
234+
onSwipeRight()
232235

233-
} else if (offsetX < -minimumSwipeDistance) {
234-
onSwipeLeft()
236+
} else if (offsetX < -minimumSwipeDistance) {
237+
onSwipeLeft()
238+
}
235239
}
236240
}
237241
}

0 commit comments

Comments
 (0)