Improve webtoon zoom fling

This commit is contained in:
vianh
2024-02-15 21:21:45 +07:00
committed by Koitharu
parent 813561fd3b
commit b4bd923ce8

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Matrix
import android.graphics.Point
import android.graphics.Rect
import android.graphics.RectF
import android.util.AttributeSet
@@ -19,12 +20,16 @@ import android.widget.OverScroller
import androidx.core.animation.doOnEnd
import androidx.core.view.GestureDetectorCompat
import androidx.core.view.ViewConfigurationCompat
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.widgets.ZoomControl
import org.koitharu.kotatsu.core.util.ext.getAnimationDuration
import kotlin.math.roundToInt
private const val MAX_SCALE = 2.5f
private const val MIN_SCALE = 0.5f
private const val FLING_RANGE = 20_000
class WebtoonScalingFrame @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
@@ -36,6 +41,7 @@ class WebtoonScalingFrame @JvmOverloads constructor(
private val scaleDetector = ScaleGestureDetector(context, this)
private val gestureDetector = GestureDetectorCompat(context, GestureListener())
private val overScroller = OverScroller(context, AccelerateDecelerateInterpolator())
private val transformMatrix = Matrix()
private val matrixValues = FloatArray(9)
private val scale
@@ -49,6 +55,7 @@ class WebtoonScalingFrame @JvmOverloads constructor(
private val translateBounds = RectF()
private val targetHitRect = Rect()
private var animator: ValueAnimator? = null
private var pendingScroll = 0
var isZoomEnable = false
set(value) {
@@ -80,7 +87,7 @@ class WebtoonScalingFrame @JvmOverloads constructor(
overScroller.forceFinished(true)
}
gestureDetector.onTouchEvent(ev)
val consumed = gestureDetector.onTouchEvent(ev)
scaleDetector.onTouchEvent(ev)
// Offset event to inside the child view
@@ -88,11 +95,7 @@ class WebtoonScalingFrame @JvmOverloads constructor(
ev.offsetLocation(halfWidth - ev.x + targetHitRect.width() / 3, 0f)
}
// Send action cancel to avoid recycler jump when scale end
if (scaleDetector.isInProgress) {
ev.action = MotionEvent.ACTION_CANCEL
}
return super.dispatchTouchEvent(ev)
return consumed || scaleDetector.isInProgress || super.dispatchTouchEvent(ev)
}
override fun onGenericMotionEvent(event: MotionEvent): Boolean {
@@ -178,6 +181,10 @@ class WebtoonScalingFrame @JvmOverloads constructor(
scaleY = scale
translationX = transX
translationY = transY
if (pendingScroll != 0) {
nestedScrollBy(0, pendingScroll)
pendingScroll = 0
}
}
val newHeight = if (scale < 1f) (height / scale).toInt() else height
@@ -210,6 +217,7 @@ class WebtoonScalingFrame @JvmOverloads constructor(
else -> 0f
}
pendingScroll = if (scale > 1) (dy / scale).roundToInt() else 0
transformMatrix.postTranslate(dx, dy)
syncMatrixValues()
}
@@ -277,6 +285,7 @@ class WebtoonScalingFrame @JvmOverloads constructor(
private fun findTargetChild() = getChildAt(0) as WebtoonRecyclerView
private inner class GestureListener : GestureDetector.SimpleOnGestureListener(), Runnable {
private val prevPos = Point()
override fun onScroll(
e1: MotionEvent?,
@@ -294,7 +303,7 @@ class WebtoonScalingFrame @JvmOverloads constructor(
val newScale = if (scale != 1f) 1f else MAX_SCALE * 0.8f
ValueAnimator.ofFloat(scale, newScale).run {
interpolator = AccelerateDecelerateInterpolator()
duration = 300
duration = context.getAnimationDuration(R.integer.config_defaultAnimTime)
addUpdateListener {
scaleChild(it.animatedValue as Float, e.x, e.y)
}
@@ -311,15 +320,16 @@ class WebtoonScalingFrame @JvmOverloads constructor(
): Boolean {
if (scale <= 1) return false
prevPos.set(transX.toInt(), transY.toInt())
overScroller.fling(
transX.toInt(),
transY.toInt(),
prevPos.x,
prevPos.y,
velocityX.toInt(),
velocityY.toInt(),
translateBounds.left.toInt(),
translateBounds.right.toInt(),
translateBounds.top.toInt(),
translateBounds.bottom.toInt(),
translateBounds.top.toInt() - FLING_RANGE,
translateBounds.bottom.toInt() + FLING_RANGE,
)
postOnAnimation(this)
return true
@@ -328,9 +338,10 @@ class WebtoonScalingFrame @JvmOverloads constructor(
override fun run() {
if (overScroller.computeScrollOffset()) {
transformMatrix.postTranslate(
overScroller.currX - transX,
overScroller.currY - transY,
overScroller.currX.toFloat() - prevPos.x,
overScroller.currY.toFloat() - prevPos.y
)
prevPos.set(overScroller.currX, overScroller.currY)
invalidateTarget()
postOnAnimation(this)
}