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 a802da9ba..1ee481db5 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 @@ -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) } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt b/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt index 0ab1cee6b..b5bfa7ee4 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt @@ -86,6 +86,9 @@ class TextChapterLayout( var channel = Channel(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() @@ -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 { - 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? = null - ): Pair { - 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,