Skip to content

Commit a6d7235

Browse files
update EnhancedZoom implementation
Fling gesture target is acquired before animation ends to have visible image section while animation is in progress
1 parent e36419c commit a6d7235

File tree

2 files changed

+32
-19
lines changed

2 files changed

+32
-19
lines changed

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

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,24 +81,23 @@ open class EnhancedZoomState constructor(
8181
)
8282

8383
private fun calculateRectBounds(): IntRect {
84-
8584
val width = size.width
8685
val height = size.height
86+
87+
val bounds = getBounds()
8788
val zoom = animatableZoom.targetValue
88-
val panX = animatablePanX.targetValue
89-
val panY = animatablePanY.targetValue
89+
val panX = animatablePanX.targetValue.coerceIn(-bounds.x, bounds.x)
90+
val panY = animatablePanY.targetValue.coerceIn(-bounds.y, bounds.y)
9091

9192
// Offset for interpolating offset from (imageWidth/2,-imageWidth/2) interval
9293
// to (0, imageWidth) interval when
9394
// transform origin is TransformOrigin(0.5f,0.5f)
9495
val horizontalCenterOffset = width * (zoom - 1) / 2f
9596
val verticalCenterOffset = height * (zoom - 1) / 2f
9697

97-
val bounds = getBounds()
98-
99-
val offsetX = (horizontalCenterOffset - panX.coerceIn(-bounds.x, bounds.x))
98+
val offsetX = (horizontalCenterOffset - panX)
10099
.coerceAtLeast(0f) / zoom
101-
val offsetY = (verticalCenterOffset - panY.coerceIn(-bounds.y, bounds.y))
100+
val offsetY = (verticalCenterOffset - panY)
102101
.coerceAtLeast(0f) / zoom
103102

104103
val offset = Offset(offsetX, offsetY)
@@ -167,18 +166,25 @@ open class BaseEnhancedZoomState constructor(
167166

168167
open suspend fun onGestureStart() = coroutineScope {}
169168

170-
open suspend fun onGestureEnd(onFinish: () -> Unit) {
169+
open suspend fun onGestureEnd(onBoundsCalculated: () -> Unit) {
171170

172171
// Gesture end might be called after second tap and we don't want to fling
173172
// or animate back to valid bounds when doubled tapped
174173
if (!doubleTapped) {
174+
175175
if (fling && zoom > 1) {
176-
fling()
176+
fling {
177+
// We get target value on start instead of updating bounds after
178+
// gesture has finished
179+
onBoundsCalculated()
180+
}
181+
} else {
182+
onBoundsCalculated()
177183
}
184+
178185
if (moveToBounds) {
179186
resetToValidBounds()
180187
}
181-
onFinish()
182188
}
183189
}
184190

@@ -224,21 +230,28 @@ open class BaseEnhancedZoomState constructor(
224230
* Create a fling gesture when user removes finger from scree to have continuous movement
225231
* until [velocityTracker] speed reached to lower bound
226232
*/
227-
private suspend fun fling() = coroutineScope {
233+
private suspend fun fling(onFlingStart: () -> Unit) = coroutineScope {
228234
val velocityTracker = velocityTracker.calculateVelocity()
229235
val velocity = Offset(velocityTracker.x, velocityTracker.y)
236+
var flingStarted = false
230237

238+
val bounds = getBounds()
231239
launch {
232240
animatablePanX.animateDecay(
233241
velocity.x,
234-
exponentialDecay(
235-
absVelocityThreshold = 20f
236-
)
242+
exponentialDecay(absVelocityThreshold = 20f),
243+
block = {
244+
// This callback returns target value of fling gesture initially
245+
if (!flingStarted) {
246+
onFlingStart()
247+
flingStarted = true
248+
}
249+
}
237250
)
238251
}
239252

240253
launch {
241-
animatablePanY.animateDecay(
254+
val animationResult = animatablePanY.animateDecay(
242255
velocity.y,
243256
exponentialDecay(
244257
absVelocityThreshold = 20f

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,26 +136,26 @@ open class ZoomState(
136136
}
137137

138138
internal suspend fun animatePanXto(panX: Float) {
139-
if (pannable) {
139+
if (pannable && pan.x != panX) {
140140
animatablePanX.animateTo(panX)
141141
}
142142
}
143143

144144
internal suspend fun animatePanYto(panY: Float) {
145-
if (pannable) {
145+
if (pannable && pan.y != panY) {
146146
animatablePanY.animateTo(panY)
147147
}
148148
}
149149

150150
internal suspend fun animateZoomTo(zoom: Float) {
151-
if (zoomable) {
151+
if (zoomable && this.zoom != zoom) {
152152
val newZoom = zoom.coerceIn(zoomMin, zoomMax)
153153
animatableZoom.animateTo(newZoom)
154154
}
155155
}
156156

157157
internal suspend fun animateRotationTo(rotation: Float) {
158-
if (rotatable) {
158+
if (rotatable && this.rotation != rotation) {
159159
animatableRotation.animateTo(rotation)
160160
}
161161
}

0 commit comments

Comments
 (0)