Webtoon reader scroll with pan

This commit is contained in:
Koitharu
2020-03-04 20:54:50 +02:00
parent a5d863c84c
commit a3dbef6bfe
6 changed files with 107 additions and 26 deletions

View File

@@ -1,16 +1,29 @@
package org.koitharu.kotatsu.ui.reader.wetoon
import android.view.Gravity
import android.view.ViewGroup
import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
import org.koitharu.kotatsu.ui.reader.PageLoader
class WebtoonAdapter(private val loader: PageLoader) : BaseRecyclerAdapter<MangaPage, Unit>() {
class WebtoonAdapter(private val loader: PageLoader) : BaseRecyclerAdapter<MangaPage, Int>() {
private var lastBound = -1
override fun onCreateViewHolder(parent: ViewGroup) =
WebtoonHolder(parent, loader)
override fun onGetItemId(item: MangaPage) = item.id
override fun getExtra(item: MangaPage, position: Int) = Unit
override fun onBindViewHolder(holder: BaseViewHolder<MangaPage, Int>, position: Int) {
super.onBindViewHolder(holder, position)
lastBound = position
}
override fun getExtra(item: MangaPage, position: Int) = if (position >= lastBound) {
Gravity.TOP
} else {
Gravity.BOTTOM
}
}

View File

@@ -0,0 +1,41 @@
package org.koitharu.kotatsu.ui.reader.wetoon
import android.content.Context
import android.graphics.RectF
import android.util.AttributeSet
import android.widget.FrameLayout
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import kotlinx.android.synthetic.main.item_page_webtoon.view.*
import org.koitharu.kotatsu.R
class WebtoonFrameLayout @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
private val pan = RectF()
private val target by lazy {
findViewById<SubsamplingScaleImageView>(R.id.ssiv)
}
fun dispatchVerticalScroll(dy: Int): Int {
target.getPanRemaining(pan)
val c = target.center ?: return 0
val s = target.scale
return when {
dy > 0 -> {
val delta = minOf(pan.bottom.toInt(), dy)
c.offset(0f, delta.toFloat() / s)
target.setScaleAndCenter(s, c)
delta
}
dy < 0 -> {
val delta = minOf(pan.top.toInt(), -dy)
c.offset(0f, -delta.toFloat() / s)
target.setScaleAndCenter(s, c)
-delta
}
else -> 0
}
}
}

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.ui.reader.wetoon
import android.graphics.PointF
import android.view.Gravity
import android.view.ViewGroup
import androidx.core.net.toUri
import androidx.core.view.isVisible
@@ -16,10 +17,11 @@ import org.koitharu.kotatsu.utils.ext.getDisplayMessage
class WebtoonHolder(parent: ViewGroup, private val loader: PageLoader) :
BaseViewHolder<MangaPage, Unit>(parent, R.layout.item_page_webtoon),
BaseViewHolder<MangaPage, Int>(parent, R.layout.item_page_webtoon),
SubsamplingScaleImageView.OnImageEventListener, CoroutineScope by loader {
private var job: Job? = null
private var yFactor = 0f
init {
ssiv.setOnImageEventListener(this)
@@ -28,7 +30,12 @@ class WebtoonHolder(parent: ViewGroup, private val loader: PageLoader) :
}
}
override fun onBind(data: MangaPage, extra: Unit) {
override fun onBind(data: MangaPage, extra: Int) {
yFactor = when(extra) {
Gravity.TOP -> 0f
Gravity.BOTTOM -> 1f
else -> 0.5f
}
doLoad(data, force = false)
}
@@ -56,7 +63,7 @@ class WebtoonHolder(parent: ViewGroup, private val loader: PageLoader) :
ssiv.minScale = ssiv.width / ssiv.sWidth.toFloat()
ssiv.setScaleAndCenter(
ssiv.minScale,
PointF(ssiv.sWidth / 2f, 0f)
PointF(ssiv.sWidth / 2f, ssiv.sHeight * yFactor)
)
}

View File

@@ -1,15 +0,0 @@
package org.koitharu.kotatsu.ui.reader.wetoon
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
class WebtoonImageView @JvmOverloads constructor(context: Context, attr: AttributeSet? = null) :
SubsamplingScaleImageView(context, attr) {
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent) = false
}

View File

@@ -3,13 +3,46 @@ package org.koitharu.kotatsu.ui.reader.wetoon
import android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.core.view.children
import androidx.recyclerview.widget.RecyclerView
class WebtoonRecyclerView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : RecyclerView(context, attrs, defStyleAttr) {
override fun onNestedPreScroll(target: View?, dx: Int, dy: Int, consumed: IntArray?) {
super.onNestedPreScroll(target, dx, dy, consumed)
override fun dispatchNestedPreScroll(
dx: Int,
dy: Int,
consumed: IntArray?,
offsetInWindow: IntArray?,
type: Int
): Boolean {
val consumedY = consumeVerticalScroll(dy)
val superRes = super.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type)
consumed?.set(1, consumed[1] + consumedY)
return superRes || consumedY != 0
}
override fun dispatchNestedPreScroll(
dx: Int,
dy: Int,
consumed: IntArray?,
offsetInWindow: IntArray?
): Boolean {
val consumedY = consumeVerticalScroll(dy)
val superRes = super.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow)
consumed?.set(1, consumed[1] + consumedY)
return superRes || consumedY != 0
}
private fun consumeVerticalScroll(dy: Int): Int {
val child = when {
dy > 0 -> children.firstOrNull { it is WebtoonFrameLayout }
dy < 0 -> children.lastOrNull { it is WebtoonFrameLayout }
else -> null
} ?: return 0
var scrollY = dy
scrollY -= (child as WebtoonFrameLayout) .dispatchVerticalScroll(scrollY)
return dy - scrollY
}
}

View File

@@ -1,14 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
<org.koitharu.kotatsu.ui.reader.wetoon.WebtoonFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.koitharu.kotatsu.ui.reader.wetoon.WebtoonImageView
<com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
android:id="@+id/ssiv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
app:panEnabled="false" />
<ProgressBar
android:id="@+id/progressBar"
@@ -48,4 +50,4 @@
</LinearLayout>
</FrameLayout>
</org.koitharu.kotatsu.ui.reader.wetoon.WebtoonFrameLayout>