|
|
|
|
@ -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,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|