优化
Some checks failed
Test Build / prepare (push) Waiting to run
Test Build / build (app, release) (push) Blocked by required conditions
Test Build / build (app, releaseA) (push) Blocked by required conditions
Test Build / prerelease (push) Blocked by required conditions
Test Build / lanzou (push) Blocked by required conditions
Test Build / test_Branch (push) Blocked by required conditions
Test Build / telegram (push) Blocked by required conditions
closeStaleIssue / stale (push) Has been cancelled

This commit is contained in:
Horis
2025-02-20 22:58:30 +08:00
parent 7f1bf0fc35
commit 0c659f7103
2 changed files with 71 additions and 137 deletions

View File

@@ -35,7 +35,8 @@ data class TextPage(
var chapterSize: Int = 0,
var chapterIndex: Int = 0,
var height: Float = 0f,
var leftLineSize: Int = 0
var leftLineSize: Int = 0,
var renderHeight: Int = 0
) {
companion object {
@@ -332,8 +333,7 @@ data class TextPage(
fun render(view: ContentTextView): Boolean {
if (!isCompleted) return false
val height = lines.lastOrNull()?.lineBottom?.toInt() ?: 0
return canvasRecorder.recordIfNeeded(view.width, height) {
return canvasRecorder.recordIfNeeded(view.width, renderHeight) {
drawPage(view, this)
}
}

View File

@@ -86,6 +86,9 @@ class TextChapterLayout(
var channel = Channel<TextPage>(Int.MAX_VALUE)
var durY = 0f
var absStartX = paddingLeft
init {
job = Coroutine.async(
scope,
@@ -127,7 +130,7 @@ class TextChapterLayout(
}
private fun onPageCompleted() {
val textPage = textPages.last()
val textPage = pendingTextPage
textPage.index = textPages.lastIndex
textPage.chapterIndex = bookChapter.index
textPage.chapterSize = chaptersSize
@@ -137,6 +140,8 @@ class TextChapterLayout(
textPage.isCompleted = true
textPage.textChapter = textChapter
textPage.upLinesPosition()
textPage.renderHeight = textPage.lines.maxOf { it.lineBottom.toInt() }
textPages.add(textPage)
channel.trySend(textPage)
try {
listener?.onLayoutPageCompleted(textPages.lastIndex, textPage)
@@ -184,16 +189,15 @@ class TextChapterLayout(
bookContent: BookContent,
) {
val contents = bookContent.textList
var absStartX = paddingLeft
var durY = 0f
val imageStyle = book.getImageStyle()
val isSingleImageStyle = imageStyle.equals(Book.imgStyleSingle, true)
val isTextImageStyle = imageStyle.equals(Book.imgStyleText, true)
if (ReadBookConfig.titleMode != 2 || bookChapter.isVolume || contents.isEmpty()) {
//标题非隐藏
displayTitle.splitNotBlank("\n").forEach { text ->
setTypeText(
book, absStartX, durY,
book,
if (AppConfig.enableReview) text + ChapterProvider.reviewChar else text,
titlePaint,
titlePaintTextHeight,
@@ -202,10 +206,7 @@ class TextChapterLayout(
isTitle = true,
emptyContent = contents.isEmpty(),
isVolumeTitle = bookChapter.isVolume
).let {
absStartX = it.first
durY = it.second
}
)
}
pendingTextPage.lines.last().isParagraphEnd = true
stringBuilder.append("\n")
@@ -213,19 +214,15 @@ class TextChapterLayout(
// 如果是单图模式且当前页有内容,强制分页
if (isSingleImageStyle && pendingTextPage.lines.isNotEmpty()) {
pendingTextPage.height = durY
textPages.add(pendingTextPage)
onPageCompleted()
pendingTextPage = TextPage()
stringBuilder.clear()
absStartX = paddingLeft
durY = 0f
prepareNextPageIfNeed()
}
}
val sb = StringBuffer()
var isSetTypedImage = false
contents.forEach { content ->
coroutineContext.ensureActive()
if (book.getImageStyle().equals(Book.imgStyleText, true)) {
if (isTextImageStyle) {
//图片样式为文字嵌入类型
var text = content.replace(ChapterProvider.srcReplaceChar, "")
val srcList = LinkedList<String>()
@@ -241,19 +238,18 @@ class TextChapterLayout(
text = sb.toString()
setTypeText(
book,
absStartX,
durY,
text,
contentPaint,
contentPaintTextHeight,
contentPaintFontMetrics,
book.getImageStyle(),
srcList = srcList
).let {
absStartX = it.first
durY = it.second
}
)
} else {
if (isSingleImageStyle && isSetTypedImage) {
isSetTypedImage = false
prepareNextPageIfNeed()
}
val matcher = AppPattern.imgPattern.matcher(content)
var start = 0
while (matcher.find()) {
@@ -262,57 +258,45 @@ class TextChapterLayout(
if (text.isNotBlank()) {
setTypeText(
book,
absStartX,
durY,
text,
contentPaint,
contentPaintTextHeight,
contentPaintFontMetrics,
book.getImageStyle(),
isFirstLine = start == 0
).let {
absStartX = it.first
durY = it.second
}
)
}
setTypeImage(
book,
matcher.group(1)!!,
absStartX,
durY,
contentPaintTextHeight,
stringBuilder,
book.getImageStyle()
).let {
absStartX = it.first
durY = it.second
}
)
isSetTypedImage = true
start = matcher.end()
}
if (start < content.length) {
if (isSingleImageStyle && isSetTypedImage) {
isSetTypedImage = false
prepareNextPageIfNeed()
}
val text = content.substring(start, content.length)
if (text.isNotBlank()) {
setTypeText(
book, absStartX, durY,
book,
if (AppConfig.enableReview) text + ChapterProvider.reviewChar else text,
contentPaint,
contentPaintTextHeight,
contentPaintFontMetrics,
book.getImageStyle(),
isFirstLine = start == 0
).let {
absStartX = it.first
durY = it.second
}
)
}
}
}
if (pendingTextPage.lines.isNotEmpty()) {
pendingTextPage.lines.last().isParagraphEnd = true
}
pendingTextPage.lines.last().isParagraphEnd = true
stringBuilder.append("\n")
}
textPages.add(pendingTextPage)
val textPage = pendingTextPage
val endPadding = 20.dpToPx()
val durYPadding = durY + endPadding
@@ -333,29 +317,12 @@ class TextChapterLayout(
private suspend fun setTypeImage(
book: Book,
src: String,
x: Int,
y: Float,
textHeight: Float,
stringBuilder: StringBuilder,
imageStyle: String?,
): Pair<Int, Float> {
var absStartX = x
var durY = y
) {
val size = ImageProvider.getImageSize(book, src, ReadBook.bookSource)
if (size.width > 0 && size.height > 0) {
if (durY > visibleHeight) {
val textPage = pendingTextPage
if (textPage.height < durY) {
textPage.height = durY
}
textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" }
stringBuilder.clear()
textPages.add(textPage)
coroutineContext.ensureActive()
onPageCompleted()
pendingTextPage = TextPage()
durY = 0f
}
prepareNextPageIfNeed(durY)
var height = size.height
var width = size.width
when (imageStyle?.uppercase()) {
@@ -372,17 +339,7 @@ class TextChapterLayout(
height = visibleHeight
}
if (durY > 0f) {
val textPage = pendingTextPage
if (textPage.height < durY) {
textPage.height = durY
}
textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" }
stringBuilder.clear()
textPages.add(textPage)
coroutineContext.ensureActive()
onPageCompleted()
pendingTextPage = TextPage()
durY = 0f
prepareNextPageIfNeed()
}
// 图片竖直方向居中:调整 Y 坐标
@@ -401,30 +358,7 @@ class TextChapterLayout(
width = width * visibleHeight / height
height = visibleHeight
}
if (durY + height > visibleHeight) {
val textPage = pendingTextPage
// 双页的 durY 不正确,可能会小于实际高度
if (textPage.height < durY) {
textPage.height = durY
}
if (doublePage && absStartX < viewWidth / 2) {
//当前页面左列结束
textPage.leftLineSize = textPage.lineSize
absStartX = viewWidth / 2 + paddingLeft
} else {
//当前页面结束
if (textPage.leftLineSize == 0) {
textPage.leftLineSize = textPage.lineSize
}
textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" }
stringBuilder.clear()
textPages.add(textPage)
coroutineContext.ensureActive()
onPageCompleted()
pendingTextPage = TextPage()
}
durY = 0f
}
prepareNextPageIfNeed(durY + height)
}
}
val textLine = TextLine(isImage = true)
@@ -439,13 +373,13 @@ class TextChapterLayout(
Pair(0f, width.toFloat())
}
textLine.addColumn(
ImageColumn(start = x + start, end = x + end, src = src)
ImageColumn(start = absStartX + start, end = absStartX + end, src = src)
)
calcTextLinePosition(textPages, textLine, stringBuilder.length)
stringBuilder.append(" ") // 确保翻页时索引计算正确
pendingTextPage.addLine(textLine)
}
return absStartX to durY + textHeight * paragraphSpacing / 10f
durY += textHeight * paragraphSpacing / 10f
}
/**
@@ -454,8 +388,6 @@ class TextChapterLayout(
@Suppress("DEPRECATION")
private suspend fun setTypeText(
book: Book,
x: Int,
y: Float,
text: String,
textPaint: TextPaint,
textHeight: Float,
@@ -466,8 +398,7 @@ class TextChapterLayout(
emptyContent: Boolean = false,
isVolumeTitle: Boolean = false,
srcList: LinkedList<String>? = null
): Pair<Int, Float> {
var absStartX = x
) {
val widthsArray = FloatArray(text.length)
textPaint.getTextWidths(text, widthsArray)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
@@ -485,7 +416,7 @@ class TextChapterLayout(
} else {
StaticLayout(text, textPaint, visibleWidth, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true)
}
var durY = when {
durY = when {
//标题y轴居中
emptyContent && textPages.isEmpty() -> {
val textPage = pendingTextPage
@@ -503,7 +434,7 @@ class TextChapterLayout(
it.lineBase -= textLayoutHeight
it.lineBottom -= textLayoutHeight
}
y - textLayoutHeight
durY - textLayoutHeight
}
}
@@ -514,39 +445,15 @@ class TextChapterLayout(
if (ty > titleTopSpacing) ty else titleTopSpacing.toFloat()
}
else -> y + titleTopSpacing
else -> durY + titleTopSpacing
}
}
else -> y
else -> durY
}
for (lineIndex in 0 until layout.lineCount) {
val textLine = TextLine(isTitle = isTitle)
if (durY + textHeight > visibleHeight) {
val textPage = pendingTextPage
if (textPage.height < durY) {
textPage.height = durY
}
if (doublePage && absStartX < viewWidth / 2) {
//当前页面左列结束
textPage.leftLineSize = textPage.lineSize
absStartX = viewWidth / 2 + paddingLeft
} else {
//当前页面结束,设置各种值
if (textPage.leftLineSize == 0) {
textPage.leftLineSize = textPage.lineSize
}
textPage.text = stringBuilder.toString()
textPages.add(textPage)
coroutineContext.ensureActive()
onPageCompleted()
//新建页面
pendingTextPage = TextPage()
stringBuilder.clear()
absStartX = paddingLeft
}
durY = 0f
}
prepareNextPageIfNeed(durY + textHeight)
val lineStart = layout.getLineStart(lineIndex)
val lineEnd = layout.getLineEnd(lineIndex)
val lineText = text.substring(lineStart, lineEnd)
@@ -615,7 +522,6 @@ class TextChapterLayout(
}
}
durY += textHeight * paragraphSpacing / 10f
return Pair(absStartX, durY)
}
private fun calcTextLinePosition(
@@ -850,6 +756,34 @@ class TextChapterLayout(
}
}
private suspend fun prepareNextPageIfNeed(requestHeight: Float = -1f) {
if (requestHeight > visibleHeight || requestHeight == -1f) {
val textPage = pendingTextPage
// 双页的 durY 不正确,可能会小于实际高度
if (textPage.height < durY) {
textPage.height = durY
}
if (doublePage && absStartX < viewWidth / 2) {
//当前页面左列结束
textPage.leftLineSize = textPage.lineSize
absStartX = viewWidth / 2 + paddingLeft
} else {
//当前页面结束,设置各种值
if (textPage.leftLineSize == 0) {
textPage.leftLineSize = textPage.lineSize
}
textPage.text = stringBuilder.toString()
coroutineContext.ensureActive()
onPageCompleted()
//新建页面
pendingTextPage = TextPage()
stringBuilder.clear()
absStartX = paddingLeft
}
durY = 0f
}
}
private fun measureTextSplit(
text: String,
widthsArray: FloatArray,