Webtoon reader improvements
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user