mirror of
https://github.com/gedoor/legado.git
synced 2025-08-10 00:52:30 +00:00
@@ -46,6 +46,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
||||
val selectEnd = TextPos(0, 0, 0)
|
||||
var textPage: TextPage = TextPage()
|
||||
private set
|
||||
var isMainView = false
|
||||
private var drawVisibleImageOnly = false
|
||||
private var cacheIncreased = false
|
||||
private val increaseSize = 8 * 1024 * 1024
|
||||
@@ -93,6 +94,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
||||
|
||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||
super.onSizeChanged(w, h, oldw, oldh)
|
||||
if (!isMainView) return
|
||||
ChapterProvider.upViewSize(w, h)
|
||||
upVisibleRect()
|
||||
textPage.format()
|
||||
@@ -468,6 +470,30 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurVisiblePage(): TextPage {
|
||||
val visiblePage = TextPage()
|
||||
var relativeOffset: Float
|
||||
for (relativePos in 0..2) {
|
||||
relativeOffset = relativeOffset(relativePos)
|
||||
if (relativePos > 0) {
|
||||
//滚动翻页
|
||||
if (!callBack.isScroll) break
|
||||
if (relativeOffset >= ChapterProvider.visibleHeight) break
|
||||
}
|
||||
val textPage = relativePage(relativePos)
|
||||
for (textLine in textPage.lines) {
|
||||
if (textLine.isVisible(relativeOffset)) {
|
||||
val visibleLine = textLine.copy().apply {
|
||||
lineTop += relativeOffset
|
||||
lineBottom += relativeOffset
|
||||
}
|
||||
visiblePage.addLine(visibleLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
return visiblePage
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择开始文字
|
||||
*/
|
||||
|
||||
@@ -337,6 +337,14 @@ class PageView(context: Context) : FrameLayout(context) {
|
||||
return binding.contentTextView.selectText(x, y - headerHeight, select)
|
||||
}
|
||||
|
||||
fun getCurVisiblePage(): TextPage {
|
||||
return binding.contentTextView.getCurVisiblePage()
|
||||
}
|
||||
|
||||
fun markAsMainView() {
|
||||
binding.contentTextView.isMainView = true
|
||||
}
|
||||
|
||||
fun selectStartMove(x: Float, y: Float) {
|
||||
binding.contentTextView.selectStartMove(x, y - headerHeight)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import io.legado.app.ui.book.read.page.api.DataSource
|
||||
import io.legado.app.ui.book.read.page.delegate.*
|
||||
import io.legado.app.ui.book.read.page.entities.PageDirection
|
||||
import io.legado.app.ui.book.read.page.entities.TextChapter
|
||||
import io.legado.app.ui.book.read.page.entities.TextPage
|
||||
import io.legado.app.ui.book.read.page.entities.TextPos
|
||||
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
||||
import io.legado.app.ui.book.read.page.provider.TextPageFactory
|
||||
@@ -104,6 +105,7 @@ class ReadView(context: Context, attrs: AttributeSet) :
|
||||
addView(prevPage)
|
||||
nextPage.invisible()
|
||||
prevPage.invisible()
|
||||
curPage.markAsMainView()
|
||||
if (!isInEditMode) {
|
||||
upBg()
|
||||
setWillNotDraw(false)
|
||||
@@ -607,6 +609,10 @@ class ReadView(context: Context, attrs: AttributeSet) :
|
||||
return curPage.selectedText
|
||||
}
|
||||
|
||||
fun getCurVisiblePage(): TextPage {
|
||||
return curPage.getCurVisiblePage()
|
||||
}
|
||||
|
||||
override val currentChapter: TextChapter?
|
||||
get() {
|
||||
return if (callBack.isInitFinish) ReadBook.textChapter(0) else null
|
||||
|
||||
@@ -3,9 +3,12 @@ package io.legado.app.ui.book.read.page.delegate
|
||||
import android.graphics.Canvas
|
||||
import android.view.MotionEvent
|
||||
import android.view.VelocityTracker
|
||||
import io.legado.app.help.book.isImage
|
||||
import io.legado.app.model.ReadBook
|
||||
import io.legado.app.ui.book.read.page.ReadView
|
||||
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
||||
|
||||
@Suppress("UnnecessaryVariable")
|
||||
class ScrollPageDelegate(readView: ReadView) : PageDelegate(readView) {
|
||||
|
||||
// 滑动追踪的时间
|
||||
@@ -102,7 +105,7 @@ class ScrollPageDelegate(readView: ReadView) : PageDelegate(readView) {
|
||||
return
|
||||
}
|
||||
readView.setStartPoint(0f, 0f, false)
|
||||
startScroll(0, 0, 0, -ChapterProvider.visibleHeight, animationSpeed)
|
||||
startScroll(0, 0, 0, calcNextPageOffset(), animationSpeed)
|
||||
}
|
||||
|
||||
override fun prevPageByAnim(animationSpeed: Int) {
|
||||
@@ -110,6 +113,38 @@ class ScrollPageDelegate(readView: ReadView) : PageDelegate(readView) {
|
||||
return
|
||||
}
|
||||
readView.setStartPoint(0f, 0f, false)
|
||||
startScroll(0, 0, 0, ChapterProvider.visibleHeight, animationSpeed)
|
||||
startScroll(0, 0, 0, calcPrevPageOffset(), animationSpeed)
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算点击翻页保留一行的滚动距离
|
||||
* 图片页使用可视高度作为滚动距离
|
||||
*/
|
||||
private fun calcNextPageOffset(): Int {
|
||||
val visibleHeight = ChapterProvider.visibleHeight
|
||||
if (ReadBook.book?.isImage == true) {
|
||||
return -visibleHeight
|
||||
}
|
||||
val visiblePage = readView.getCurVisiblePage()
|
||||
if (visiblePage.isImageOrEmpty()) {
|
||||
return -visibleHeight
|
||||
}
|
||||
val lastLineTop = visiblePage.lines.last().lineTop.toInt()
|
||||
val offset = lastLineTop - ChapterProvider.paddingTop
|
||||
return -offset
|
||||
}
|
||||
|
||||
private fun calcPrevPageOffset(): Int {
|
||||
val visibleHeight = ChapterProvider.visibleHeight
|
||||
if (ReadBook.book?.isImage == true) {
|
||||
return visibleHeight
|
||||
}
|
||||
val visiblePage = readView.getCurVisiblePage()
|
||||
if (visiblePage.isImageOrEmpty()) {
|
||||
return visibleHeight
|
||||
}
|
||||
val firstLineBottom = visiblePage.lines.first().lineBottom.toInt()
|
||||
val offset = visibleHeight - (firstLineBottom - ChapterProvider.paddingTop)
|
||||
return offset
|
||||
}
|
||||
}
|
||||
@@ -61,4 +61,39 @@ data class TextLine(
|
||||
return y > lineTop + relativeOffset
|
||||
&& y < lineBottom + relativeOffset
|
||||
}
|
||||
|
||||
fun isVisible(relativeOffset: Float): Boolean {
|
||||
val top = lineTop + relativeOffset
|
||||
val bottom = lineBottom + relativeOffset
|
||||
val width = bottom - top
|
||||
val visibleTop = ChapterProvider.paddingTop
|
||||
val visibleBottom = ChapterProvider.visibleBottom
|
||||
val visible = when {
|
||||
// 完全可视
|
||||
top >= visibleTop && bottom <= visibleBottom -> true
|
||||
top <= visibleTop && bottom >= visibleBottom -> true
|
||||
// 上方第一行部分可视
|
||||
top < visibleTop && bottom > visibleTop && bottom < visibleBottom -> {
|
||||
if (isImage) {
|
||||
true
|
||||
} else {
|
||||
val visibleRate = (bottom - visibleTop) / width
|
||||
visibleRate > 0.6
|
||||
}
|
||||
}
|
||||
// 下方第一行部分可视
|
||||
top > visibleTop && top < visibleBottom && bottom > visibleBottom -> {
|
||||
if (isImage) {
|
||||
true
|
||||
} else {
|
||||
val visibleRate = (visibleBottom - top) / width
|
||||
visibleRate > 0.6
|
||||
}
|
||||
}
|
||||
// 不可视
|
||||
else -> false
|
||||
}
|
||||
return visible
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -230,4 +230,8 @@ data class TextPage(
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun isImageOrEmpty(): Boolean {
|
||||
return textLines.all { it.isTitle || it.isImage }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="ImageContrastCheck" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vw_bg"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#50000000" />
|
||||
|
||||
<io.legado.app.ui.widget.TitleBar
|
||||
android:id="@+id/title_bar"
|
||||
android:layout_width="match_parent"
|
||||
@@ -24,10 +30,8 @@
|
||||
app:themeMode="dark" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/vw_bg"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:background="#50000000"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintTop_toBottomOf="@id/title_bar"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
||||
Reference in New Issue
Block a user