mirror of
https://github.com/gedoor/legado.git
synced 2024-07-06 23:47:49 +08:00
优化
This commit is contained in:
parent
822db28d88
commit
92d6e00ab0
@ -422,7 +422,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
|
||||
var curLine = curTextLines[lineIndex]
|
||||
length = length - currentPage.text.length + curLine.text.length
|
||||
if (curLine.isParagraphEnd) length++
|
||||
while (length < contentPosition && lineIndex + 1 < curTextLines.size) {
|
||||
while (length <= contentPosition && lineIndex + 1 < curTextLines.size) {
|
||||
lineIndex += 1
|
||||
curLine = curTextLines[lineIndex]
|
||||
length += curLine.text.length
|
||||
|
@ -2,13 +2,18 @@ package io.legado.app.ui.book.read.page.entities
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint.FontMetrics
|
||||
import android.os.Build
|
||||
import androidx.annotation.Keep
|
||||
import androidx.core.graphics.withTranslation
|
||||
import io.legado.app.help.PaintPool
|
||||
import io.legado.app.help.book.isImage
|
||||
import io.legado.app.help.config.ReadBookConfig
|
||||
import io.legado.app.lib.theme.ThemeStore
|
||||
import io.legado.app.model.ReadBook
|
||||
import io.legado.app.ui.book.read.page.ContentTextView
|
||||
import io.legado.app.ui.book.read.page.entities.TextPage.Companion.emptyTextPage
|
||||
import io.legado.app.ui.book.read.page.entities.column.BaseColumn
|
||||
import io.legado.app.ui.book.read.page.entities.column.TextColumn
|
||||
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
||||
import io.legado.app.utils.canvasrecorder.CanvasRecorderFactory
|
||||
import io.legado.app.utils.canvasrecorder.recordIfNeededThenDraw
|
||||
@ -32,6 +37,13 @@ data class TextLine(
|
||||
val isTitle: Boolean = false,
|
||||
var isParagraphEnd: Boolean = false,
|
||||
var isImage: Boolean = false,
|
||||
var startX: Float = 0f,
|
||||
var indentSize: Int = 0,
|
||||
var extraLetterSpacing: Float = 0f,
|
||||
var extraLetterSpacingOffsetX: Float = 0f,
|
||||
var wordSpacing: Float = 0f,
|
||||
var exceed: Boolean = false,
|
||||
var onlyTextColumn: Boolean = true,
|
||||
) {
|
||||
|
||||
val columns: List<BaseColumn> get() = textColumns
|
||||
@ -41,6 +53,7 @@ data class TextLine(
|
||||
val chapterIndices: IntRange get() = chapterPosition..chapterPosition + charSize
|
||||
val height: Float inline get() = lineBottom - lineTop
|
||||
val canvasRecorder = CanvasRecorderFactory.create()
|
||||
var searchResultColumnCount = 0
|
||||
var isReadAloud: Boolean = false
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
@ -52,6 +65,9 @@ data class TextLine(
|
||||
var isLeftLine = true
|
||||
|
||||
fun addColumn(column: BaseColumn) {
|
||||
if (column !is TextColumn) {
|
||||
onlyTextColumn = false
|
||||
}
|
||||
column.textLine = this
|
||||
textColumns.add(column)
|
||||
}
|
||||
@ -129,14 +145,56 @@ data class TextLine(
|
||||
}
|
||||
|
||||
private fun drawTextLine(view: ContentTextView, canvas: Canvas) {
|
||||
for (i in columns.indices) {
|
||||
columns[i].draw(view, canvas)
|
||||
if (checkFastDraw()) {
|
||||
fastDrawTextLine(view, canvas)
|
||||
} else {
|
||||
for (i in columns.indices) {
|
||||
columns[i].draw(view, canvas)
|
||||
}
|
||||
}
|
||||
if (ReadBookConfig.underline && !isImage && ReadBook.book?.isImage != true) {
|
||||
drawUnderline(canvas)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fastDrawTextLine(view: ContentTextView, canvas: Canvas) {
|
||||
val textPaint = if (isTitle) {
|
||||
ChapterProvider.titlePaint
|
||||
} else {
|
||||
ChapterProvider.contentPaint
|
||||
}
|
||||
val textColor = if (isReadAloud) {
|
||||
ThemeStore.accentColor
|
||||
} else {
|
||||
ReadBookConfig.textColor
|
||||
}
|
||||
val paint = PaintPool.obtain()
|
||||
paint.set(textPaint)
|
||||
if (extraLetterSpacing != 0f) {
|
||||
paint.letterSpacing += extraLetterSpacing
|
||||
}
|
||||
if (wordSpacing != 0f) {
|
||||
paint.wordSpacing += wordSpacing
|
||||
}
|
||||
if (paint.color != textColor) {
|
||||
paint.color = textColor
|
||||
}
|
||||
if (extraLetterSpacingOffsetX != 0f) {
|
||||
canvas.withTranslation(extraLetterSpacingOffsetX) {
|
||||
canvas.drawText(text, indentSize, text.length, startX, lineBase - lineTop, paint)
|
||||
}
|
||||
} else {
|
||||
canvas.drawText(text, indentSize, text.length, startX, lineBase - lineTop, paint)
|
||||
}
|
||||
PaintPool.recycle(paint)
|
||||
for (i in columns.indices) {
|
||||
val column = columns[i] as TextColumn
|
||||
if (column.selected) {
|
||||
canvas.drawRect(column.start, 0f, column.end, height, view.selectedPaint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制下划线
|
||||
*/
|
||||
@ -151,6 +209,16 @@ data class TextLine(
|
||||
)
|
||||
}
|
||||
|
||||
fun checkFastDraw(): Boolean {
|
||||
if (exceed || !onlyTextColumn || textPage.isMsgPage) {
|
||||
return false
|
||||
}
|
||||
if (!atLeastApi29 && wordSpacing != 0f) {
|
||||
return false
|
||||
}
|
||||
return searchResultColumnCount == 0
|
||||
}
|
||||
|
||||
fun invalidate() {
|
||||
invalidateSelf()
|
||||
textPage.invalidate()
|
||||
@ -166,6 +234,7 @@ data class TextLine(
|
||||
|
||||
companion object {
|
||||
val emptyTextLine = TextLine()
|
||||
private val atLeastApi29 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
package io.legado.app.ui.book.read.page.entities
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.text.Layout
|
||||
import android.text.StaticLayout
|
||||
import androidx.annotation.Keep
|
||||
import androidx.core.graphics.withTranslation
|
||||
import io.legado.app.R
|
||||
import io.legado.app.help.PaintPool
|
||||
import io.legado.app.help.config.ReadBookConfig
|
||||
import io.legado.app.ui.book.read.page.ContentTextView
|
||||
import io.legado.app.ui.book.read.page.entities.TextChapter.Companion.emptyTextChapter
|
||||
@ -13,6 +15,7 @@ import io.legado.app.ui.book.read.page.entities.column.TextColumn
|
||||
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
||||
import io.legado.app.utils.canvasrecorder.CanvasRecorderFactory
|
||||
import io.legado.app.utils.canvasrecorder.recordIfNeeded
|
||||
import io.legado.app.utils.dpToPx
|
||||
import splitties.init.appCtx
|
||||
import java.text.DecimalFormat
|
||||
import kotlin.math.min
|
||||
@ -277,6 +280,21 @@ data class TextPage(
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawDebugInfo(canvas: Canvas) {
|
||||
ChapterProvider.run {
|
||||
val paint = PaintPool.obtain()
|
||||
paint.style = Paint.Style.STROKE
|
||||
canvas.drawRect(
|
||||
paddingLeft.toFloat(),
|
||||
0f,
|
||||
(paddingLeft + visibleWidth).toFloat(),
|
||||
height - 1.dpToPx(),
|
||||
paint
|
||||
)
|
||||
PaintPool.recycle(paint)
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawPage(view: ContentTextView, canvas: Canvas) {
|
||||
for (i in lines.indices) {
|
||||
val line = lines[i]
|
||||
|
@ -33,6 +33,11 @@ data class TextColumn(
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
textLine.invalidate()
|
||||
if (value) {
|
||||
textLine.searchResultColumnCount++
|
||||
} else {
|
||||
textLine.searchResultColumnCount--
|
||||
}
|
||||
}
|
||||
field = value
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import kotlinx.coroutines.launch
|
||||
import java.util.LinkedList
|
||||
import java.util.Locale
|
||||
import kotlin.coroutines.coroutineContext
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class TextChapterLayout(
|
||||
scope: CoroutineScope,
|
||||
@ -467,7 +468,7 @@ class TextChapterLayout(
|
||||
//第一行 非标题
|
||||
textLine.text = lineText
|
||||
addCharsToLineFirst(
|
||||
book, absStartX, textLine, words,
|
||||
book, absStartX, textLine, words, textPaint,
|
||||
desiredWidth, widths, srcList
|
||||
)
|
||||
}
|
||||
@ -505,7 +506,7 @@ class TextChapterLayout(
|
||||
//中间行
|
||||
textLine.text = lineText
|
||||
addCharsToLineMiddle(
|
||||
book, absStartX, textLine, words,
|
||||
book, absStartX, textLine, words, textPaint,
|
||||
desiredWidth, 0f, widths, srcList
|
||||
)
|
||||
}
|
||||
@ -556,6 +557,7 @@ class TextChapterLayout(
|
||||
absStartX: Int,
|
||||
textLine: TextLine,
|
||||
words: List<String>,
|
||||
textPaint: TextPaint,
|
||||
/**自然排版长度**/
|
||||
desiredWidth: Float,
|
||||
textWidths: List<Float>,
|
||||
@ -582,11 +584,12 @@ class TextChapterLayout(
|
||||
x = x1
|
||||
textLine.indentWidth = x
|
||||
}
|
||||
textLine.indentSize = bodyIndent.length
|
||||
if (words.size > bodyIndent.length) {
|
||||
val text1 = words.subList(bodyIndent.length, words.size)
|
||||
val textWidths1 = textWidths.subList(bodyIndent.length, textWidths.size)
|
||||
addCharsToLineMiddle(
|
||||
book, absStartX, textLine, text1,
|
||||
book, absStartX, textLine, text1, textPaint,
|
||||
desiredWidth, x, textWidths1, srcList
|
||||
)
|
||||
}
|
||||
@ -600,6 +603,7 @@ class TextChapterLayout(
|
||||
absStartX: Int,
|
||||
textLine: TextLine,
|
||||
words: List<String>,
|
||||
textPaint: TextPaint,
|
||||
/**自然排版长度**/
|
||||
desiredWidth: Float,
|
||||
/**起始x坐标**/
|
||||
@ -616,8 +620,10 @@ class TextChapterLayout(
|
||||
}
|
||||
val residualWidth = visibleWidth - desiredWidth
|
||||
val spaceSize = words.count { it == " " }
|
||||
textLine.startX = absStartX + startX
|
||||
if (spaceSize > 1) {
|
||||
val d = residualWidth / spaceSize
|
||||
val d = residualWidth / (spaceSize - 1)
|
||||
textLine.wordSpacing = d
|
||||
var x = startX
|
||||
for (index in words.indices) {
|
||||
val char = words[index]
|
||||
@ -636,6 +642,8 @@ class TextChapterLayout(
|
||||
} else {
|
||||
val gapCount: Int = words.lastIndex
|
||||
val d = residualWidth / gapCount
|
||||
textLine.extraLetterSpacingOffsetX = -d / 2
|
||||
textLine.extraLetterSpacing = d / textPaint.textSize
|
||||
var x = startX
|
||||
for (index in words.indices) {
|
||||
val char = words[index]
|
||||
@ -666,6 +674,7 @@ class TextChapterLayout(
|
||||
) {
|
||||
val indentLength = ReadBookConfig.paragraphIndent.length
|
||||
var x = startX
|
||||
textLine.startX = absStartX + startX
|
||||
for (index in words.indices) {
|
||||
val char = words[index]
|
||||
val cw = textWidths[index]
|
||||
@ -727,8 +736,9 @@ class TextChapterLayout(
|
||||
*/
|
||||
private fun exceed(absStartX: Int, textLine: TextLine, words: List<String>) {
|
||||
val visibleEnd = absStartX + visibleWidth
|
||||
val endX = textLine.columns.lastOrNull()?.end ?: return
|
||||
val endX = textLine.columns.lastOrNull()?.end?.roundToInt() ?: return
|
||||
if (endX > visibleEnd) {
|
||||
textLine.exceed = true
|
||||
val cc = (endX - visibleEnd) / words.size
|
||||
for (i in 0..words.lastIndex) {
|
||||
textLine.getColumnReverseAt(i).let {
|
||||
|
Loading…
Reference in New Issue
Block a user