From 078ef17a3adcf8d5515cd5bd9adc81962feaa594 Mon Sep 17 00:00:00 2001 From: plr Date: Fri, 3 Jul 2020 13:10:19 +0200 Subject: [PATCH] Ability to set animation interpolator --- Readme.md | 4 +- mapview/build.gradle | 2 +- .../mapview/layout/GestureLayout.kt | 43 ++++++++++++------- .../layout/animators/ZoomPanAnimator.kt | 12 +++--- 4 files changed, 38 insertions(+), 23 deletions(-) diff --git a/Readme.md b/Readme.md index 68f7f7a..ab86566 100644 --- a/Readme.md +++ b/Readme.md @@ -1,4 +1,4 @@ -[ ![Download](https://api.bintray.com/packages/peterlaurence/maven/mapview/images/download.svg?version=2.0.9) ](https://bintray.com/peterlaurence/maven/mapview/2.0.9/link) +[ ![Download](https://api.bintray.com/packages/peterlaurence/maven/mapview/images/download.svg?version=2.0.10) ](https://bintray.com/peterlaurence/maven/mapview/2.0.10/link) # MapView @@ -60,7 +60,7 @@ There are some breaking changes, although most of them are just package refactor Add this to your module's build.gradle ```groovy -implementation 'com.peterlaurence:mapview:2.0.9' +implementation 'com.peterlaurence:mapview:2.0.10' ``` ## Origin and motivation diff --git a/mapview/build.gradle b/mapview/build.gradle index 908da29..0090e3c 100644 --- a/mapview/build.gradle +++ b/mapview/build.gradle @@ -5,7 +5,7 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlinx-serialization' -def versionTag = "2.0.9" +def versionTag = "2.0.10" androidExtensions { experimental = true diff --git a/mapview/src/main/java/com/peterlaurence/mapview/layout/GestureLayout.kt b/mapview/src/main/java/com/peterlaurence/mapview/layout/GestureLayout.kt index 79d76c2..b573720 100644 --- a/mapview/src/main/java/com/peterlaurence/mapview/layout/GestureLayout.kt +++ b/mapview/src/main/java/com/peterlaurence/mapview/layout/GestureLayout.kt @@ -3,6 +3,9 @@ package com.peterlaurence.mapview.layout import android.content.Context import android.util.AttributeSet import android.view.* +import android.view.animation.AccelerateDecelerateInterpolator +import android.view.animation.DecelerateInterpolator +import android.view.animation.Interpolator import android.widget.Scroller import androidx.core.view.ViewCompat import com.peterlaurence.mapview.layout.animators.ZoomPanAnimator @@ -25,9 +28,11 @@ abstract class GestureLayout @JvmOverloads constructor(context: Context, attrs: TouchUpGestureDetector.OnTouchUpListener, RotationGestureDetector.OnRotationGestureListener, GestureController.Controllable { - /* Controllers */ internal val gestureController: GestureController by lazy { GestureController(this) } + private val defaultInterpolator: Interpolator = AccelerateDecelerateInterpolator() + private val fastInterpolator: Interpolator = DecelerateInterpolator(2f) + override fun onMinScaleUpdateRequest() { gestureController.calculateMinimumScaleToFit(width, height) } @@ -220,9 +225,10 @@ abstract class GestureLayout @JvmOverloads constructor(context: Context, attrs: * * @param x Horizontal destination point. * @param y Vertical destination point. + * @param interpolator The [Interpolator] the animation should use. */ - fun slideTo(x: Int, y: Int) { - animator.animatePan(x, y) + fun slideTo(x: Int, y: Int, interpolator: Interpolator = defaultInterpolator) { + animator.animatePan(x, y, interpolator) } /** @@ -230,10 +236,11 @@ abstract class GestureLayout @JvmOverloads constructor(context: Context, attrs: * * @param x Horizontal destination point. * @param y Vertical destination point. + * @param interpolator The [Interpolator] the animation should use. */ @Suppress("unused") - fun slideToAndCenter(x: Int, y: Int) { - slideTo(x - halfWidth, y - halfHeight) + fun slideToAndCenter(x: Int, y: Int, interpolator: Interpolator = defaultInterpolator) { + slideTo(x - halfWidth, y - halfHeight, interpolator) } /** @@ -243,18 +250,21 @@ abstract class GestureLayout @JvmOverloads constructor(context: Context, attrs: * @param x Horizontal destination point. * @param y Vertical destination point. * @param scale The final scale value the layout should animate to. + * @param interpolator The [Interpolator] the animation should use. */ - fun slideToAndCenterWithScale(x: Int, y: Int, scale: Float) { - animator.animateZoomPan(x - halfWidth, y - halfHeight, scale) + fun slideToAndCenterWithScale(x: Int, y: Int, scale: Float, interpolator: Interpolator = defaultInterpolator) { + animator.animateZoomPan(x - halfWidth, y - halfHeight, scale, interpolator) } /** * Scales the [GestureLayout] with animated progress, without maintaining scroll position. * * @param destination The final scale value the layout should animate to. + * @param interpolator The [Interpolator] the animation should use. */ - fun smoothScaleTo(destination: Float) { - animator.animateZoom(destination) + @Suppress("unused") + fun smoothScaleTo(destination: Float, interpolator: Interpolator = defaultInterpolator) { + animator.animateZoom(destination, interpolator) } /** @@ -264,22 +274,25 @@ abstract class GestureLayout @JvmOverloads constructor(context: Context, attrs: * @param focusX The horizontal focal point to maintain, relative to the screen (as supplied by MotionEvent.getX). * @param focusY The vertical focal point to maintain, relative to the screen (as supplied by MotionEvent.getY). * @param scale The final scale value the layout should animate to. + * @param interpolator The [Interpolator] the animation should use. */ - fun smoothScaleFromFocalPoint(focusX: Int, focusY: Int, scale: Float) { + fun smoothScaleFromFocalPoint(focusX: Int, focusY: Int, scale: Float, interpolator: Interpolator = defaultInterpolator) { val (x, y, scaleCst) = gestureController.getOffsetDestination(focusX, focusY, scale) if (scaleCst == gestureController.scale) { return } - animator.animateZoomPan(x, y, scaleCst) + animator.animateZoomPan(x, y, scaleCst, interpolator) } /** * Animate the scale of the [GestureLayout] while maintaining the current center point. * * @param scale The final scale value the layout should animate to. + * @param interpolator The [Interpolator] the animation should use. */ - fun smoothScaleFromCenter(scale: Float) { - smoothScaleFromFocalPoint(halfWidth, halfHeight, scale) + @Suppress("unused") + fun smoothScaleFromCenter(scale: Float, interpolator: Interpolator = defaultInterpolator) { + smoothScaleFromFocalPoint(halfWidth, halfHeight, scale, interpolator) } override fun constrainScrollToLimits() { @@ -404,14 +417,14 @@ abstract class GestureLayout @JvmOverloads constructor(context: Context, attrs: gestureController.scale) if (gestureController.angle == 0f) { - smoothScaleFromFocalPoint(event.x.toInt(), event.y.toInt(), scaleCst) + smoothScaleFromFocalPoint(event.x.toInt(), event.y.toInt(), scaleCst, fastInterpolator) } else { val angleRad = -gestureController.angle.toRad() val eventRx = (height / 2 * sin(angleRad) + width / 2 * (1 - cos(angleRad)) + event.x * cos(angleRad) - event.y * sin(angleRad)).toInt() val eventRy = (height / 2 * (1 - cos(angleRad)) - width / 2 * sin(angleRad) + event.x * sin(angleRad) + event.y * cos(angleRad)).toInt() - smoothScaleFromFocalPoint(eventRx, eventRy, scaleCst) + smoothScaleFromFocalPoint(eventRx, eventRy, scaleCst, fastInterpolator) } return true diff --git a/mapview/src/main/java/com/peterlaurence/mapview/layout/animators/ZoomPanAnimator.kt b/mapview/src/main/java/com/peterlaurence/mapview/layout/animators/ZoomPanAnimator.kt index a649b18..a6c0aa1 100644 --- a/mapview/src/main/java/com/peterlaurence/mapview/layout/animators/ZoomPanAnimator.kt +++ b/mapview/src/main/java/com/peterlaurence/mapview/layout/animators/ZoomPanAnimator.kt @@ -2,7 +2,7 @@ package com.peterlaurence.mapview.layout.animators import android.animation.Animator import android.animation.ValueAnimator -import android.view.animation.AccelerateInterpolator +import android.view.animation.Interpolator class ZoomPanAnimator(private val listener: OnZoomPanAnimationListener) : ValueAnimator(), ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener { @@ -16,7 +16,6 @@ class ZoomPanAnimator(private val listener: OnZoomPanAnimationListener) : ValueA addUpdateListener(this) addListener(this) setFloatValues(0f, 1f) - interpolator = AccelerateInterpolator() } private fun setupPanAnimation(x: Int, y: Int): Boolean { @@ -33,24 +32,27 @@ class ZoomPanAnimator(private val listener: OnZoomPanAnimationListener) : ValueA return startState.scale != endState.scale } - fun animateZoomPan(x: Int, y: Int, scale: Float) { + fun animateZoomPan(x: Int, y: Int, scale: Float, interpolator: Interpolator) { hasPendingZoomUpdates = setupZoomAnimation(scale) hasPendingPanUpdates = setupPanAnimation(x, y) if (hasPendingPanUpdates || hasPendingZoomUpdates) { + this.interpolator = interpolator start() } } - fun animateZoom(scale: Float) { + fun animateZoom(scale: Float, interpolator: Interpolator) { hasPendingZoomUpdates = setupZoomAnimation(scale) if (hasPendingZoomUpdates) { + this.interpolator = interpolator start() } } - fun animatePan(x: Int, y: Int) { + fun animatePan(x: Int, y: Int, interpolator: Interpolator) { hasPendingPanUpdates = setupPanAnimation(x, y) if (hasPendingPanUpdates) { + this.interpolator = interpolator start() } }