@@ -46,6 +46,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
val selectEnd = TextPos(0, 0, 0)
|
val selectEnd = TextPos(0, 0, 0)
|
||||||
var textPage: TextPage = TextPage()
|
var textPage: TextPage = TextPage()
|
||||||
private set
|
private set
|
||||||
|
var isMainView = false
|
||||||
private var drawVisibleImageOnly = false
|
private var drawVisibleImageOnly = false
|
||||||
private var cacheIncreased = false
|
private var cacheIncreased = false
|
||||||
private val increaseSize = 8 * 1024 * 1024
|
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) {
|
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||||
super.onSizeChanged(w, h, oldw, oldh)
|
super.onSizeChanged(w, h, oldw, oldh)
|
||||||
|
if (!isMainView) return
|
||||||
ChapterProvider.upViewSize(w, h)
|
ChapterProvider.upViewSize(w, h)
|
||||||
upVisibleRect()
|
upVisibleRect()
|
||||||
textPage.format()
|
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)
|
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) {
|
fun selectStartMove(x: Float, y: Float) {
|
||||||
binding.contentTextView.selectStartMove(x, y - headerHeight)
|
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.delegate.*
|
||||||
import io.legado.app.ui.book.read.page.entities.PageDirection
|
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.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.entities.TextPos
|
||||||
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
||||||
import io.legado.app.ui.book.read.page.provider.TextPageFactory
|
import io.legado.app.ui.book.read.page.provider.TextPageFactory
|
||||||
@@ -104,6 +105,7 @@ class ReadView(context: Context, attrs: AttributeSet) :
|
|||||||
addView(prevPage)
|
addView(prevPage)
|
||||||
nextPage.invisible()
|
nextPage.invisible()
|
||||||
prevPage.invisible()
|
prevPage.invisible()
|
||||||
|
curPage.markAsMainView()
|
||||||
if (!isInEditMode) {
|
if (!isInEditMode) {
|
||||||
upBg()
|
upBg()
|
||||||
setWillNotDraw(false)
|
setWillNotDraw(false)
|
||||||
@@ -607,6 +609,10 @@ class ReadView(context: Context, attrs: AttributeSet) :
|
|||||||
return curPage.selectedText
|
return curPage.selectedText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getCurVisiblePage(): TextPage {
|
||||||
|
return curPage.getCurVisiblePage()
|
||||||
|
}
|
||||||
|
|
||||||
override val currentChapter: TextChapter?
|
override val currentChapter: TextChapter?
|
||||||
get() {
|
get() {
|
||||||
return if (callBack.isInitFinish) ReadBook.textChapter(0) else null
|
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.graphics.Canvas
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.VelocityTracker
|
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.ReadView
|
||||||
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
||||||
|
|
||||||
|
@Suppress("UnnecessaryVariable")
|
||||||
class ScrollPageDelegate(readView: ReadView) : PageDelegate(readView) {
|
class ScrollPageDelegate(readView: ReadView) : PageDelegate(readView) {
|
||||||
|
|
||||||
// 滑动追踪的时间
|
// 滑动追踪的时间
|
||||||
@@ -102,7 +105,7 @@ class ScrollPageDelegate(readView: ReadView) : PageDelegate(readView) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
readView.setStartPoint(0f, 0f, false)
|
readView.setStartPoint(0f, 0f, false)
|
||||||
startScroll(0, 0, 0, -ChapterProvider.visibleHeight, animationSpeed)
|
startScroll(0, 0, 0, calcNextPageOffset(), animationSpeed)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun prevPageByAnim(animationSpeed: Int) {
|
override fun prevPageByAnim(animationSpeed: Int) {
|
||||||
@@ -110,6 +113,38 @@ class ScrollPageDelegate(readView: ReadView) : PageDelegate(readView) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
readView.setStartPoint(0f, 0f, false)
|
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
|
return y > lineTop + relativeOffset
|
||||||
&& y < lineBottom + 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
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isImageOrEmpty(): Boolean {
|
||||||
|
return textLines.all { it.isTitle || it.isImage }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,12 @@
|
|||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:ignore="ImageContrastCheck" />
|
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
|
<io.legado.app.ui.widget.TitleBar
|
||||||
android:id="@+id/title_bar"
|
android:id="@+id/title_bar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -24,10 +30,8 @@
|
|||||||
app:themeMode="dark" />
|
app:themeMode="dark" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/vw_bg"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:background="#50000000"
|
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layout_constraintTop_toBottomOf="@id/title_bar"
|
app:layout_constraintTop_toBottomOf="@id/title_bar"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
|||||||
Reference in New Issue
Block a user