diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
index 1ce08d25e..f33b1ff2e 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
@@ -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
+ }
+
/**
* 选择开始文字
*/
diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
index 048f9725b..ba727f60e 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
@@ -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)
}
diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ReadView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ReadView.kt
index b482e95d3..80ce5c30f 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/ReadView.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/ReadView.kt
@@ -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
diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt
index 26e8f98b0..fefeba8d6 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt
@@ -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
}
}
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt
index 59d9b24db..11a3cf970 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt
@@ -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
+ }
+
}
diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt
index 69899d87c..346e651cd 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt
@@ -230,4 +230,8 @@ data class TextPage(
}
return null
}
+
+ fun isImageOrEmpty(): Boolean {
+ return textLines.all { it.isTitle || it.isImage }
+ }
}
diff --git a/app/src/main/res/layout-land/activity_book_info.xml b/app/src/main/res/layout-land/activity_book_info.xml
index fd93ebfed..1cacb5629 100644
--- a/app/src/main/res/layout-land/activity_book_info.xml
+++ b/app/src/main/res/layout-land/activity_book_info.xml
@@ -15,6 +15,12 @@
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ImageContrastCheck" />
+
+