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" /> + +