Webtoon reader improvements

This commit is contained in:
Koitharu
2024-02-07 10:25:23 +02:00
parent 2d909854fb
commit ba2ed6a2ef
2 changed files with 27 additions and 66 deletions

View File

@@ -80,26 +80,28 @@ class WebtoonImageView @JvmOverloads constructor(
val parentHeight = MeasureSpec.getSize(heightMeasureSpec)
val resizeWidth = widthSpecMode != MeasureSpec.EXACTLY
val resizeHeight = heightSpecMode != MeasureSpec.EXACTLY
var width = parentWidth
var height = parentHeight
var desiredWidth = parentWidth
var desiredHeight = parentHeight
if (sWidth > 0 && sHeight > 0) {
if (resizeWidth && resizeHeight) {
width = sWidth
height = sHeight
desiredWidth = sWidth
desiredHeight = sHeight
} else if (resizeHeight) {
height = (sHeight.toDouble() / sWidth.toDouble() * width).toInt()
desiredHeight = (sHeight.toDouble() / sWidth.toDouble() * desiredWidth).roundToInt()
} else if (resizeWidth) {
width = (sWidth.toDouble() / sHeight.toDouble() * height).toInt()
desiredWidth = (sWidth.toDouble() / sHeight.toDouble() * desiredHeight).roundToInt()
}
}
width = width.coerceAtLeast(suggestedMinimumWidth)
height = height.coerceAtLeast(suggestedMinimumHeight).coerceAtMost(parentHeight())
setMeasuredDimension(width, height)
desiredWidth = desiredWidth.coerceAtLeast(suggestedMinimumWidth)
desiredHeight = desiredHeight.coerceAtLeast(suggestedMinimumHeight).coerceAtMost(parentHeight())
setMeasuredDimension(desiredWidth, desiredHeight)
}
override fun onDownsamplingChanged() {
super.onDownsamplingChanged()
adjustScale()
post {
adjustScale()
}
}
override fun onReady() {
@@ -107,15 +109,6 @@ class WebtoonImageView @JvmOverloads constructor(
adjustScale()
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
if (oldh != h && oldw != 0 && oldh != 0 && isReady) {
ancestors.firstNotNullOfOrNull { it as? WebtoonRecyclerView }?.updateChildrenScroll()
} else {
return
}
}
private fun scrollToInternal(pos: Int) {
minScale = width / sWidth.toFloat()
maxScale = minScale
@@ -128,6 +121,7 @@ class WebtoonImageView @JvmOverloads constructor(
minScale = width / sWidth.toFloat()
maxScale = minScale
minimumScaleType = SCALE_TYPE_CUSTOM
requestLayout()
}
private fun parentHeight(): Int {

View File

@@ -5,9 +5,9 @@ import android.util.AttributeSet
import android.view.View
import androidx.core.view.ViewCompat.TYPE_TOUCH
import androidx.core.view.forEach
import androidx.core.view.iterator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.util.Collections
import java.util.LinkedList
import java.util.WeakHashMap
@@ -17,12 +17,11 @@ class WebtoonRecyclerView @JvmOverloads constructor(
private var onPageScrollListeners = LinkedList<OnWebtoonScrollListener>()
private val scrollDispatcher = WebtoonScrollDispatcher()
private val detachedViews = WeakHashMap<View, Unit>()
private var isFixingScroll: Boolean = false
private val detachedViews = Collections.newSetFromMap(WeakHashMap<View, Boolean>())
override fun onChildDetachedFromWindow(child: View) {
super.onChildDetachedFromWindow(child)
detachedViews[child] = Unit
detachedViews.add(child)
}
override fun onChildAttachedToWindow(child: View) {
@@ -32,7 +31,7 @@ class WebtoonRecyclerView @JvmOverloads constructor(
override fun startNestedScroll(axes: Int) = startNestedScroll(axes, TYPE_TOUCH)
override fun startNestedScroll(axes: Int, type: Int): Boolean = true
override fun startNestedScroll(axes: Int, type: Int): Boolean = childCount != 0
override fun dispatchNestedPreScroll(
dx: Int,
@@ -57,13 +56,6 @@ class WebtoonRecyclerView @JvmOverloads constructor(
return consumedY != 0 || dy == 0
}
override fun onScrollStateChanged(state: Int) {
super.onScrollStateChanged(state)
if (state == SCROLL_STATE_IDLE) {
updateChildrenScroll()
}
}
private fun consumeVerticalScroll(dy: Int): Int {
if (childCount == 0) {
return 0
@@ -124,43 +116,11 @@ class WebtoonRecyclerView @JvmOverloads constructor(
forEach { child ->
(child as WebtoonFrameLayout).target.requestLayout()
}
detachedViews.keys.forEach { child ->
detachedViews.forEach { child ->
(child as WebtoonFrameLayout).target.requestLayout()
}
}
fun updateChildrenScroll() {
if (isFixingScroll) {
return
}
isFixingScroll = true
for (child in this) {
val ssiv = (child as WebtoonFrameLayout).target
if (adjustScroll(child, ssiv)) {
break
}
}
isFixingScroll = false
}
private fun adjustScroll(child: View, ssiv: WebtoonImageView): Boolean = when {
child.bottom < height && ssiv.getScroll() < ssiv.getScrollRange() -> {
val distance = minOf(height - child.bottom, ssiv.getScrollRange() - ssiv.getScroll())
scrollBy(0, -distance)
ssiv.scrollBy(distance)
true
}
child.top > 0 && ssiv.getScroll() > 0 -> {
val distance = minOf(child.top, ssiv.getScroll())
scrollBy(0, distance)
ssiv.scrollBy(-distance)
true
}
else -> false
}
private class WebtoonScrollDispatcher {
private var firstPos = NO_POSITION
@@ -178,13 +138,20 @@ class WebtoonRecyclerView @JvmOverloads constructor(
if (newFirstPos != firstPos || newLastPos != lastPos) {
firstPos = newFirstPos
lastPos = newLastPos
rv.onPageScrollListeners.forEach { it.onScrollChanged(rv, dy, newFirstPos, newLastPos) }
if (newFirstPos != NO_POSITION && newLastPos != NO_POSITION) {
rv.onPageScrollListeners.forEach { it.onScrollChanged(rv, dy, newFirstPos, newLastPos) }
}
}
}
}
interface OnWebtoonScrollListener {
fun onScrollChanged(recyclerView: WebtoonRecyclerView, dy: Int, firstVisiblePosition: Int, lastVisiblePosition: Int)
fun onScrollChanged(
recyclerView: WebtoonRecyclerView,
dy: Int,
firstVisiblePosition: Int,
lastVisiblePosition: Int,
)
}
}