Webtoon reader improvements

master
Koitharu 2 years ago
parent 2d909854fb
commit ba2ed6a2ef
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

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

@ -5,9 +5,9 @@ import android.util.AttributeSet
import android.view.View import android.view.View
import androidx.core.view.ViewCompat.TYPE_TOUCH import androidx.core.view.ViewCompat.TYPE_TOUCH
import androidx.core.view.forEach import androidx.core.view.forEach
import androidx.core.view.iterator
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import java.util.Collections
import java.util.LinkedList import java.util.LinkedList
import java.util.WeakHashMap import java.util.WeakHashMap
@ -17,12 +17,11 @@ class WebtoonRecyclerView @JvmOverloads constructor(
private var onPageScrollListeners = LinkedList<OnWebtoonScrollListener>() private var onPageScrollListeners = LinkedList<OnWebtoonScrollListener>()
private val scrollDispatcher = WebtoonScrollDispatcher() private val scrollDispatcher = WebtoonScrollDispatcher()
private val detachedViews = WeakHashMap<View, Unit>() private val detachedViews = Collections.newSetFromMap(WeakHashMap<View, Boolean>())
private var isFixingScroll: Boolean = false
override fun onChildDetachedFromWindow(child: View) { override fun onChildDetachedFromWindow(child: View) {
super.onChildDetachedFromWindow(child) super.onChildDetachedFromWindow(child)
detachedViews[child] = Unit detachedViews.add(child)
} }
override fun onChildAttachedToWindow(child: View) { 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) = 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( override fun dispatchNestedPreScroll(
dx: Int, dx: Int,
@ -57,13 +56,6 @@ class WebtoonRecyclerView @JvmOverloads constructor(
return consumedY != 0 || dy == 0 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 { private fun consumeVerticalScroll(dy: Int): Int {
if (childCount == 0) { if (childCount == 0) {
return 0 return 0
@ -124,43 +116,11 @@ class WebtoonRecyclerView @JvmOverloads constructor(
forEach { child -> forEach { child ->
(child as WebtoonFrameLayout).target.requestLayout() (child as WebtoonFrameLayout).target.requestLayout()
} }
detachedViews.keys.forEach { child -> detachedViews.forEach { child ->
(child as WebtoonFrameLayout).target.requestLayout() (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 class WebtoonScrollDispatcher {
private var firstPos = NO_POSITION private var firstPos = NO_POSITION
@ -178,13 +138,20 @@ class WebtoonRecyclerView @JvmOverloads constructor(
if (newFirstPos != firstPos || newLastPos != lastPos) { if (newFirstPos != firstPos || newLastPos != lastPos) {
firstPos = newFirstPos firstPos = newFirstPos
lastPos = newLastPos 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 { interface OnWebtoonScrollListener {
fun onScrollChanged(recyclerView: WebtoonRecyclerView, dy: Int, firstVisiblePosition: Int, lastVisiblePosition: Int) fun onScrollChanged(
recyclerView: WebtoonRecyclerView,
dy: Int,
firstVisiblePosition: Int,
lastVisiblePosition: Int,
)
} }
} }

Loading…
Cancel
Save