diff --git a/app/src/main/java/io/legado/app/help/config/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/config/ReadBookConfig.kt index ec8e9e03d..2e986e11a 100644 --- a/app/src/main/java/io/legado/app/help/config/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/config/ReadBookConfig.kt @@ -328,6 +328,12 @@ object ReadBookConfig { config.titleLineSpacingExtra = value } + var titleLineSpacingSub: Int + get() = config.titleLineSpacingSub + set(value) { + config.titleLineSpacingSub = value + } + var paragraphSpacing: Int get() = config.paragraphSpacing set(value) { @@ -577,6 +583,7 @@ object ReadBookConfig { exportConfig.shadowDy = shareConfig.shadowDy exportConfig.titleBold = shareConfig.titleBold exportConfig.titleLineSpacingExtra = shareConfig.titleLineSpacingExtra + exportConfig.titleLineSpacingSub = shareConfig.titleLineSpacingSub exportConfig.titleSegType = shareConfig.titleSegType exportConfig.titleSegScaling = shareConfig.titleSegScaling exportConfig.titleSegDistance = shareConfig.titleSegDistance @@ -694,6 +701,7 @@ object ReadBookConfig { var titleBottomSpacing: Int = 0, var titleBold: Int = 500,//是否粗体字 0:正常, 1:粗体, 2:细体 var titleLineSpacingExtra: Int = 12, + var titleLineSpacingSub: Int = 12, var titleSegType: Int = 0,//分段模式 var titleSegScaling: Float = 1f,//分段缩放,第二段与第一段的字体大小比例 var titleSegDistance: Int = 4,//分段判断,第几个字符开始分段 diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/TipConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/TipConfigDialog.kt index 43603a540..70198dc21 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/TipConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/TipConfigDialog.kt @@ -173,6 +173,7 @@ class TipConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_tip_config binding.dsbTitleSegScaling.progress = ReadBookConfig.titleSegScaling.toInt() * 10 binding.dsbTitleLineSpacingExtra.progress = ReadBookConfig.titleLineSpacingExtra + binding.dsbTitleLineSpacingSub.progress = ReadBookConfig.titleLineSpacingSub binding.dsbTitleSize.progress = ReadBookConfig.titleSize binding.dsbTitleTop.progress = ReadBookConfig.titleTopSpacing binding.dsbTitleBottom.progress = ReadBookConfig.titleBottomSpacing @@ -193,6 +194,10 @@ class TipConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_tip_config ReadBookConfig.titleLineSpacingExtra = it postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5)) } + binding.dsbTitleLineSpacingSub.onChanged = { + ReadBookConfig.titleLineSpacingSub = it + postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5)) + } dsbTitleSize.onChanged = { ReadBookConfig.titleSize = it postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5)) 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 8e722738b..9e54a9932 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 @@ -35,6 +35,7 @@ data class TextLine( var chapterPosition: Int = 0, var pagePosition: Int = 0, val isTitle: Boolean = false, + var titleTextSize: Float? = null, var isParagraphEnd: Boolean = false, var isImage: Boolean = false, var isHtml: Boolean = false, diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TitleSegment.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TitleSegment.kt new file mode 100644 index 000000000..5ae44fa6d --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TitleSegment.kt @@ -0,0 +1,7 @@ +package io.legado.app.ui.book.read.page.entities + +data class TitleSegment( + val text: String, + val isMainTitle: Boolean, + val scale: Float +) \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/column/TextColumn.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/column/TextColumn.kt index 8e39aee26..a6b38e6e7 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/entities/column/TextColumn.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/column/TextColumn.kt @@ -52,6 +52,10 @@ data class TextColumn( } else { ReadBookConfig.textColor } + val originalSize = textPaint.textSize + textLine.titleTextSize?.let { + textPaint.textSize = it + } if (textPaint.color != textColor) { textPaint.color = textColor } @@ -66,6 +70,7 @@ data class TextColumn( if (selected) { canvas.drawRect(start, 0f, end, textLine.height, view.selectedPaint) } + textPaint.textSize = originalSize } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt index 217558a0d..6c8dca72b 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt @@ -114,7 +114,10 @@ object ChapterProvider { var lineSpacingExtra = 0f private set - var titleLineSpacingExtra = 0f + var titleLineSpacingExtra = 0f + private set + + var titleLineSpacingSub = 0f private set @JvmStatic @@ -886,6 +889,7 @@ object ChapterProvider { //间距 lineSpacingExtra = ReadBookConfig.lineSpacingExtra / 10f titleLineSpacingExtra = ReadBookConfig.titleLineSpacingExtra / 10f + titleLineSpacingSub = ReadBookConfig.titleLineSpacingSub / 10f paragraphSpacing = ReadBookConfig.paragraphSpacing titleTopSpacing = ReadBookConfig.titleTopSpacing.dpToPx() titleBottomSpacing = ReadBookConfig.titleBottomSpacing.dpToPx() 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 49684dfc3..cd52c8d76 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 @@ -77,6 +77,8 @@ class TextChapterLayout( private val titleTopSpacing = ChapterProvider.titleTopSpacing private val titleBottomSpacing = ChapterProvider.titleBottomSpacing + private val titleLineSpacingExtra = ChapterProvider.titleLineSpacingExtra + private val titleLineSpacingSub = ChapterProvider.titleLineSpacingSub private val lineSpacingExtra = ChapterProvider.lineSpacingExtra private val paragraphSpacing = ChapterProvider.paragraphSpacing @@ -209,44 +211,6 @@ class TextChapterLayout( } } - private fun parseTitleSegments( - rawTitle: String, - segType: Int, - segDistance: Int, - segFlag: String - ): List { - if (rawTitle.isBlank()) return emptyList() - - return when (segType) { - 0 -> listOf(rawTitle) - - 1 -> { - if (segDistance <= 0 || segDistance >= rawTitle.length) - listOf(rawTitle) - else - listOf( - rawTitle.take(segDistance), - rawTitle.substring(segDistance) - ) - } - - 2 -> { - val flags = segFlag.split(",").map { it.trim() }.filter { it.isNotEmpty() } - if (flags.isEmpty()) return listOf(rawTitle) - - val pattern = flags.joinToString("|") { Regex.escape(it) } - val regex = Regex("(?<=$pattern)") - val segments = rawTitle.split(regex) - .map { it.trim() } - .filter { it.isNotEmpty() } - - segments.ifEmpty { listOf(rawTitle) } - } - - else -> listOf(rawTitle) - } - } - /** * 获取拆分完的章节数据 */ @@ -262,45 +226,66 @@ class TextChapterLayout( val isTextImageStyle = imageStyle.equals(Book.imgStyleText, true) if (titleMode != 2 || bookChapter.isVolume || contents.isEmpty()) { - val baseTitles = displayTitle.splitNotBlank("\n") - baseTitles.forEach { rawTitle -> - val titleSegments = parseTitleSegments( + val allTitleSegments = displayTitle.splitNotBlank("\n").flatMap { rawTitle -> + TitleStyleParser.getSegments( rawTitle, titleSegType, titleSegDistance, - titleSegFlag + titleSegFlag, + titleSegScaling ) - titleSegments.forEachIndexed { index, segment -> - val srcList = LinkedList() - val reviewImg = bookChapter.reviewImg - var reviewTxt = "" - if (reviewImg != null) { - srcList.add(reviewImg) - reviewTxt = if (reviewImg.contains("TEXT")) { - reviewChar - } else { - srcReplaceChar - } + } + + allTitleSegments.forEachIndexed { index, segment -> + val currentPaint: TextPaint + val currentHeight: Float + val currentMetrics: Paint.FontMetrics + val lineIndexBefore = pendingTextPage.lines.size + if (segment.isMainTitle) { + currentPaint = titlePaint + currentHeight = titlePaintTextHeight + currentMetrics = titlePaintFontMetrics + } else { + currentPaint = TextPaint(titlePaint).apply { + textSize = titlePaint.textSize * segment.scale } - val paint = if (index == 0) titlePaint else { - TextPaint(titlePaint).apply { - textSize = titlePaint.textSize * titleSegScaling - } + currentMetrics = currentPaint.fontMetrics + currentHeight = currentMetrics.bottom - currentMetrics.top + } + + val srcList = LinkedList() + val reviewImg = bookChapter.reviewImg + var reviewTxt = "" + if (index == allTitleSegments.lastIndex && reviewImg != null) { + srcList.add(reviewImg) + reviewTxt = if (reviewImg.contains("TEXT")) reviewChar else srcReplaceChar + } + + setTypeText( + book = book, + text = segment.text + reviewTxt, + textPaint = currentPaint, + textHeight = currentHeight, + fontMetrics = currentMetrics, + imageStyle = imageStyle, + srcList = srcList.ifEmpty { null }, + isTitle = true, + emptyContent = contents.isEmpty(), + isVolumeTitle = bookChapter.isVolume + ) + + if (segment.scale != 1.0f) { + val currentLines = pendingTextPage.lines + for (i in lineIndexBefore until currentLines.size) { + currentLines[i].titleTextSize = currentPaint.textSize } - setTypeText( - book, - segment + reviewTxt, - paint, - titlePaintTextHeight, - titlePaintFontMetrics, - imageStyle, - srcList = srcList.ifEmpty { null }, - isTitle = true, - emptyContent = contents.isEmpty(), - isVolumeTitle = bookChapter.isVolume - ) - pendingTextPage.lines.last().isParagraphEnd = true - stringBuilder.append("\n") + } + + pendingTextPage.lines.last().isParagraphEnd = true + stringBuilder.append("\n") + + if (index < allTitleSegments.lastIndex) { + durY += currentHeight * titleLineSpacingSub } } durY += titleBottomSpacing @@ -901,7 +886,7 @@ class TextChapterLayout( textLine.upTopBottom(durY, textHeight, fontMetrics) val textPage = pendingTextPage textPage.addLine(textLine) - durY += textHeight * lineSpacingExtra + durY += textHeight * if (isTitle) titleLineSpacingExtra else lineSpacingExtra if (textPage.height < durY) { textPage.height = durY } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/provider/TitleStyleParser.kt b/app/src/main/java/io/legado/app/ui/book/read/page/provider/TitleStyleParser.kt new file mode 100644 index 000000000..bffcd27a3 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/book/read/page/provider/TitleStyleParser.kt @@ -0,0 +1,45 @@ +package io.legado.app.ui.book.read.page.provider + +import io.legado.app.ui.book.read.page.entities.TitleSegment + +object TitleStyleParser { + fun getSegments( + rawTitle: String, + segType: Int, + segDistance: Int, + segFlag: String, + scaling: Float + ): List { + if (rawTitle.isBlank()) return emptyList() + + val results: List = when (segType) { + 1 -> { + if (segDistance <= 0 || segDistance >= rawTitle.length) + listOf(rawTitle) + else + listOf(rawTitle.take(segDistance), rawTitle.substring(segDistance)) + } + + 2 -> { + val flags = segFlag.split(",").map { it.trim() }.filter { it.isNotEmpty() } + if (flags.isEmpty()) listOf(rawTitle) + else { + val pattern = flags.joinToString("|") { Regex.escape(it) } + val regex = Regex("(?<=$pattern)") + rawTitle.split(regex).map { it.trim() }.filter { it.isNotEmpty() } + } + } + + else -> listOf(rawTitle) + } + + // 统一包装成对象返回 + return results.mapIndexed { index, text -> + TitleSegment( + text = text, + isMainTitle = index == 0, + scale = if (index == 0) 1.0f else scaling + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_tip_config.xml b/app/src/main/res/layout/dialog_tip_config.xml index d67bd81b1..03b940dc6 100644 --- a/app/src/main/res/layout/dialog_tip_config.xml +++ b/app/src/main/res/layout/dialog_tip_config.xml @@ -1,7 +1,6 @@ @@ -37,45 +36,58 @@ - + android:gravity="center_vertical" + android:orientation="horizontal"> - - - + android:text="@string/body_title" + android:textSize="16sp" + android:textStyle="bold" /> - + + + android:layout_marginVertical="8dp" + app:selectionRequired="true" + app:singleLine="true" + app:singleSelection="true"> - + + + + + + + + - + app:title="次行缩放" /> + + + + + + + + android:layout_weight="1" />