[优化] 优化标题分段功能,现在提供完整的次行缩放、距离、段距等调整
This commit is contained in:
@@ -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,//分段判断,第几个字符开始分段
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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<String> {
|
||||
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<String>()
|
||||
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<String>()
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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<TitleSegment> {
|
||||
if (rawTitle.isBlank()) return emptyList()
|
||||
|
||||
val results: List<String> = 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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user