@@ -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
0 commit comments