diff --git a/app/src/main/java/se/ajpanton/notificationlog/ZoomImageView.kt b/app/src/main/java/se/ajpanton/notificationlog/ZoomImageView.kt index 8c483bd..55a75b2 100644 --- a/app/src/main/java/se/ajpanton/notificationlog/ZoomImageView.kt +++ b/app/src/main/java/se/ajpanton/notificationlog/ZoomImageView.kt @@ -8,10 +8,7 @@ import android.util.AttributeSet import android.view.GestureDetector import android.view.MotionEvent import android.view.ScaleGestureDetector -import android.view.ViewConfiguration import androidx.appcompat.widget.AppCompatImageView -import kotlin.math.abs -import kotlin.math.exp /** A fit-to-screen image which supports pinch zoom and one-finger panning. */ class ZoomImageView @JvmOverloads constructor( @@ -29,13 +26,7 @@ class ZoomImageView @JvmOverloads constructor( private var dragging = false private var lastFocusX = 0f private var lastFocusY = 0f - private var doubleTapZooming = false - private var doubleTapMoved = false - private var doubleTapX = 0f - private var doubleTapY = 0f - private var doubleTapStartY = 0f - private var doubleTapBaseScale = 1f - private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop + private var pointerCount = 0 private val scaleDetector = ScaleGestureDetector(context, object : ScaleGestureDetector.SimpleOnScaleGestureListener() { override fun onScaleBegin(detector: ScaleGestureDetector): Boolean { lastFocusX = detector.focusX @@ -44,10 +35,13 @@ class ZoomImageView @JvmOverloads constructor( } override fun onScale(detector: ScaleGestureDetector): Boolean { - // A ScaleGestureDetector reports focus movement even when the two - // fingers stay the same distance apart, which is two-finger panning. + // Focus movement while two fingers are down is two-finger panning. + // Quick scale has one pointer, so it remains pure zoom around its + // built-in double-tap anchor. setScaleAround((currentScale * detector.scaleFactor).coerceIn(minimumScale, minimumScale * MAX_ZOOM), detector.focusX, detector.focusY) - transform.postTranslate(detector.focusX - lastFocusX, detector.focusY - lastFocusY) + if (pointerCount >= 2) { + transform.postTranslate(detector.focusX - lastFocusX, detector.focusY - lastFocusY) + } lastFocusX = detector.focusX lastFocusY = detector.focusY constrain() @@ -60,45 +54,11 @@ class ZoomImageView @JvmOverloads constructor( return true } - override fun onDoubleTap(event: MotionEvent): Boolean = true - - override fun onDoubleTapEvent(event: MotionEvent): Boolean { - when (event.actionMasked) { - MotionEvent.ACTION_DOWN -> { - doubleTapZooming = true - doubleTapMoved = false - doubleTapX = event.x - doubleTapY = event.y - doubleTapStartY = event.y - doubleTapBaseScale = currentScale - } - MotionEvent.ACTION_MOVE -> if (doubleTapZooming) { - val distance = doubleTapStartY - event.y - if (abs(distance) > touchSlop) doubleTapMoved = true - val target = (doubleTapBaseScale * exp((distance / DOUBLE_TAP_DRAG_DISTANCE).toDouble()).toFloat()) - .coerceIn(minimumScale, minimumScale * MAX_ZOOM) - setScaleAround(target, doubleTapX, doubleTapY) - constrain() - } - MotionEvent.ACTION_UP -> if (doubleTapZooming) { - if (!doubleTapMoved) { - val target = if (currentScale > minimumScale * 1.1f) minimumScale else minimumScale * DOUBLE_TAP_ZOOM - setScaleAround(target, doubleTapX, doubleTapY) - constrain() - } - doubleTapZooming = false - } - MotionEvent.ACTION_CANCEL -> doubleTapZooming = false - } - return true - } }) init { scaleType = ScaleType.MATRIX - // We implement double-tap-and-drag ourselves below. Leaving Android's - // quick-scale enabled makes both handlers modify the same matrix. - scaleDetector.isQuickScaleEnabled = false + scaleDetector.isQuickScaleEnabled = true } override fun setImageBitmap(bitmap: Bitmap?) { @@ -112,6 +72,7 @@ class ZoomImageView @JvmOverloads constructor( } override fun onTouchEvent(event: MotionEvent): Boolean { + pointerCount = event.pointerCount scaleDetector.onTouchEvent(event) gestureDetector.onTouchEvent(event) when (event.actionMasked) { @@ -120,7 +81,7 @@ class ZoomImageView @JvmOverloads constructor( lastY = event.y dragging = false } - MotionEvent.ACTION_MOVE -> if (event.pointerCount == 1 && !scaleDetector.isInProgress && !doubleTapZooming) { + MotionEvent.ACTION_MOVE -> if (event.pointerCount == 1 && !scaleDetector.isInProgress) { val dx = event.x - lastX val dy = event.y - lastY if (dx != 0f || dy != 0f) { @@ -186,7 +147,5 @@ class ZoomImageView @JvmOverloads constructor( private companion object { const val MAX_ZOOM = 6f - const val DOUBLE_TAP_ZOOM = 2.5f - const val DOUBLE_TAP_DRAG_DISTANCE = 280f } }