横屏双页

pull/1352/head
gedoor 3 years ago
parent 73a14a6d0a
commit e3e7756e39
  1. 52
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt
  2. 168
      app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt

@ -10,7 +10,7 @@ import splitties.init.appCtx
import java.text.DecimalFormat
import kotlin.math.min
@Suppress("unused")
@Suppress("unused", "MemberVisibilityCanBePrivate")
data class TextPage(
var index: Int = 0,
var text: String = appCtx.getString(R.string.data_loading),
@ -20,6 +20,7 @@ data class TextPage(
var chapterSize: Int = 0,
var chapterIndex: Int = 0,
var height: Float = 0f,
var leftLineSize: Int = 0
) {
val lineSize get() = textLines.size
@ -31,28 +32,53 @@ data class TextPage(
}
}
fun upLinesPosition() = ChapterProvider.apply {
if (!ReadBookConfig.textBottomJustify) return@apply
if (textLines.size <= 1) return@apply
if (textLines.last().isImage) return@apply
if (visibleHeight - height >= with(textLines.last()) { lineBottom - lineTop }) return@apply
val surplus = (visibleBottom - textLines.last().lineBottom)
if (surplus == 0f) return@apply
fun upLinesPosition() {
if (!ReadBookConfig.textBottomJustify) return
if (textLines.size <= 1) return
if (leftLineSize == 0) {
leftLineSize = lineSize
}
ChapterProvider.run {
val lastLine = textLines[leftLineSize - 1]
if (lastLine.isImage) return@run
val lastLineHeight = with(lastLine) { lineBottom - lineTop }
if (visibleHeight - lastLine.lineBottom >= lastLineHeight) return@run
val surplus = (visibleBottom - lastLine.lineBottom)
if (surplus == 0f) return@run
height += surplus
val tj = surplus / (textLines.size - 1)
for (i in 1 until textLines.size) {
val tj = surplus / (leftLineSize - 1)
for (i in 1 until leftLineSize) {
val line = textLines[i]
line.lineTop = line.lineTop + tj * i
line.lineBase = line.lineBase + tj * i
line.lineBottom = line.lineBottom + tj * i
}
}
if (leftLineSize == lineSize) return
ChapterProvider.run {
val lastLine = textLines.last()
if (lastLine.isImage) return@run
val lastLineHeight = with(lastLine) { lineBottom - lineTop }
if (visibleHeight - lastLine.lineBottom >= lastLineHeight) return@run
val surplus = (visibleBottom - lastLine.lineBottom)
if (surplus == 0f) return@run
val tj = surplus / (textLines.size - leftLineSize - 1)
for (i in leftLineSize + 1 until textLines.size) {
val line = textLines[i]
val surplusIndex = i - leftLineSize
line.lineTop = line.lineTop + tj * surplusIndex
line.lineBase = line.lineBase + tj * surplusIndex
line.lineBottom = line.lineBottom + tj * surplusIndex
}
}
}
@Suppress("DEPRECATION")
fun format(): TextPage {
if (textLines.isEmpty() && ChapterProvider.visibleWidth > 0) {
if (textLines.isEmpty() && ChapterProvider.viewWidth > 0) {
val visibleWidth = ChapterProvider.visibleRight - ChapterProvider.paddingLeft
val layout = StaticLayout(
text, ChapterProvider.contentPaint, ChapterProvider.visibleWidth,
text, ChapterProvider.contentPaint, visibleWidth,
Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false
)
var y = (ChapterProvider.visibleHeight - layout.height) / 2f
@ -65,7 +91,7 @@ data class TextPage(
textLine.lineBottom =
ChapterProvider.paddingTop + y + layout.getLineBottom(lineIndex)
var x = ChapterProvider.paddingLeft +
(ChapterProvider.visibleWidth - layout.getLineMax(lineIndex)) / 2
(visibleWidth - layout.getLineMax(lineIndex)) / 2
textLine.text =
text.substring(layout.getLineStart(lineIndex), layout.getLineEnd(lineIndex))
for (i in textLine.text.indices) {

@ -29,25 +29,40 @@ object ChapterProvider {
private const val srcReplaceChar = ""
@JvmStatic
private var viewWidth = 0
var viewWidth = 0
private set
@JvmStatic
private var viewHeight = 0
var viewHeight = 0
private set
@JvmStatic
var paddingLeft = 0
private set
@JvmStatic
var paddingTop = 0
private set
@JvmStatic
var paddingRight = 0
private set
@JvmStatic
var paddingBottom = 0
private set
@JvmStatic
var visibleWidth = 0
private set
@JvmStatic
var visibleHeight = 0
private set
@JvmStatic
var visibleRight = 0
private set
@JvmStatic
var visibleBottom = 0
@ -73,7 +88,7 @@ object ChapterProvider {
@JvmStatic
val contentPaint: TextPaint = TextPaint()
var isHorizontal = false
var doublePage = false
init {
@ -92,6 +107,7 @@ object ChapterProvider {
): TextChapter {
val textPages = arrayListOf<TextPage>()
val stringBuilder = StringBuilder()
var absStartX = paddingLeft
var durY = 0f
textPages.add(TextPage())
contents.forEachIndexed { index, content ->
@ -112,10 +128,13 @@ object ChapterProvider {
val isTitle = index == 0
val textPaint = if (isTitle) titlePaint else contentPaint
if (!(isTitle && ReadBookConfig.titleMode == 2)) {
durY = setTypeText(
text, durY, textPages, stringBuilder,
setTypeText(
absStartX, durY, text, textPages, stringBuilder,
isTitle, textPaint, srcList
)
).let {
absStartX = it.first
durY = it.second
}
}
} else if (book.getImageStyle() != Book.imgStyleText) {
val matcher = AppPattern.imgPattern.matcher(content)
@ -126,10 +145,13 @@ object ChapterProvider {
val isTitle = index == 0
val textPaint = if (isTitle) titlePaint else contentPaint
if (!(isTitle && ReadBookConfig.titleMode == 2)) {
durY = setTypeText(
text, durY, textPages,
setTypeText(
absStartX, durY, text, textPages,
stringBuilder, isTitle, textPaint
)
).let {
absStartX = it.first
durY = it.second
}
}
}
durY = setTypeImage(
@ -144,10 +166,13 @@ object ChapterProvider {
val isTitle = index == 0
val textPaint = if (isTitle) titlePaint else contentPaint
if (!(isTitle && ReadBookConfig.titleMode == 2)) {
durY = setTypeText(
text, durY, textPages,
setTypeText(
absStartX, durY, text, textPages,
stringBuilder, isTitle, textPaint
)
).let {
absStartX = it.first
durY = it.second
}
}
}
}
@ -240,14 +265,16 @@ object ChapterProvider {
* 排版文字
*/
private fun setTypeText(
text: String,
x: Int,
y: Float,
text: String,
textPages: ArrayList<TextPage>,
stringBuilder: StringBuilder,
isTitle: Boolean,
textPaint: TextPaint,
srcList: LinkedList<String>? = null
): Float {
): Pair<Int, Float> {
var absStartX = x
var durY = if (isTitle) y + titleTopSpacing else y
val layout = if (ReadBookConfig.useZhLayout) {
ZhLayout(text, textPaint, visibleWidth)
@ -256,6 +283,25 @@ object ChapterProvider {
)
for (lineIndex in 0 until layout.lineCount) {
val textLine = TextLine(isTitle = isTitle)
if (durY + textPaint.textHeight > visibleHeight) {
val textPage = textPages.last()
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()
textPage.height = durY
//新建页面
textPages.add(TextPage())
stringBuilder.clear()
absStartX = paddingLeft
}
durY = 0f
}
val words =
text.substring(layout.getLineStart(lineIndex), layout.getLineEnd(lineIndex))
val desiredWidth = layout.getLineWidth(lineIndex)
@ -264,6 +310,7 @@ object ChapterProvider {
//第一行
textLine.text = words
addCharsToLineFirst(
absStartX,
textLine,
words.toStringArray(),
textPaint,
@ -274,14 +321,22 @@ object ChapterProvider {
//最后一行
textLine.text = "$words\n"
isLastLine = true
val x = if (isTitle && ReadBookConfig.titleMode == 1)
val startX = if (isTitle && ReadBookConfig.titleMode == 1)
(visibleWidth - layout.getLineWidth(lineIndex)) / 2
else 0f
addCharsToLineLast(textLine, words.toStringArray(), textPaint, x, srcList)
addCharsToLineLast(
absStartX,
textLine,
words.toStringArray(),
textPaint,
startX,
srcList
)
} else {
//中间行
textLine.text = words
addCharsToLineMiddle(
absStartX,
textLine,
words.toStringArray(),
textPaint,
@ -290,15 +345,6 @@ object ChapterProvider {
srcList
)
}
if (durY + textPaint.textHeight > visibleHeight) {
//当前页面结束,设置各种值
textPages.last().text = stringBuilder.toString()
textPages.last().height = durY
//新建页面
textPages.add(TextPage())
stringBuilder.clear()
durY = 0f
}
stringBuilder.append(words)
if (isLastLine) stringBuilder.append("\n")
textPages.last().textLines.add(textLine)
@ -308,13 +354,14 @@ object ChapterProvider {
}
if (isTitle) durY += titleBottomSpacing
durY += textPaint.textHeight * paragraphSpacing / 10f
return durY
return Pair(absStartX, durY)
}
/**
* 有缩进,两端对齐
*/
private fun addCharsToLineFirst(
absStartX: Int,
textLine: TextLine,
words: Array<String>,
textPaint: TextPaint,
@ -323,34 +370,23 @@ object ChapterProvider {
) {
var x = 0f
if (!ReadBookConfig.textFullJustify) {
addCharsToLineLast(textLine, words, textPaint, x, srcList)
addCharsToLineLast(absStartX, textLine, words, textPaint, x, srcList)
return
}
val bodyIndent = ReadBookConfig.paragraphIndent
val icw = StaticLayout.getDesiredWidth(bodyIndent, textPaint) / bodyIndent.length
bodyIndent.toStringArray().forEach {
val x1 = x + icw
if (srcList != null && it == srcReplaceChar) {
textLine.textChars.add(
TextChar(
srcList.removeFirst(),
start = paddingLeft + x,
end = paddingLeft + x1,
isImage = true
)
)
} else {
textLine.textChars.add(
TextChar(
it, start = paddingLeft + x, end = paddingLeft + x1
it, start = absStartX + x, end = absStartX + x1
)
)
}
x = x1
}
if (words.size > bodyIndent.length) {
val words1 = words.copyOfRange(bodyIndent.length, words.size)
addCharsToLineMiddle(textLine, words1, textPaint, desiredWidth, x, srcList)
addCharsToLineMiddle(absStartX, textLine, words1, textPaint, desiredWidth, x, srcList)
}
}
@ -358,6 +394,7 @@ object ChapterProvider {
* 无缩进,两端对齐
*/
private fun addCharsToLineMiddle(
absStartX: Int,
textLine: TextLine,
words: Array<String>,
textPaint: TextPaint,
@ -366,7 +403,7 @@ object ChapterProvider {
srcList: LinkedList<String>?
) {
if (!ReadBookConfig.textFullJustify) {
addCharsToLineLast(textLine, words, textPaint, startX, srcList)
addCharsToLineLast(absStartX, textLine, words, textPaint, startX, srcList)
return
}
val gapCount: Int = words.lastIndex
@ -379,15 +416,15 @@ object ChapterProvider {
textLine.textChars.add(
TextChar(
srcList.removeFirst(),
start = paddingLeft + x,
end = paddingLeft + x1,
start = absStartX + x,
end = absStartX + x1,
isImage = true
)
)
} else {
textLine.textChars.add(
TextChar(
s, start = paddingLeft + x, end = paddingLeft + x1
s, start = absStartX + x, end = absStartX + x1
)
)
}
@ -400,6 +437,7 @@ object ChapterProvider {
* 最后一行,自然排列
*/
private fun addCharsToLineLast(
absStartX: Int,
textLine: TextLine,
words: Array<String>,
textPaint: TextPaint,
@ -414,15 +452,15 @@ object ChapterProvider {
textLine.textChars.add(
TextChar(
srcList.removeFirst(),
start = paddingLeft + x,
end = paddingLeft + x1,
start = absStartX + x,
end = absStartX + x1,
isImage = true
)
)
} else {
textLine.textChars.add(
TextChar(
it, start = paddingLeft + x, end = paddingLeft + x1
it, start = absStartX + x, end = absStartX + x1
)
)
}
@ -435,17 +473,17 @@ object ChapterProvider {
* 超出边界处理
*/
private fun exceed(textLine: TextLine, words: Array<String>) {
val endX = textLine.textChars.lastOrNull()?.end ?: return
if (endX > visibleRight) {
val cc = (endX - visibleRight) / words.size
for (i in 0..words.lastIndex) {
textLine.getTextCharReverseAt(i).let {
val py = cc * (words.size - i)
it.start = it.start - py
it.end = it.end - py
}
}
}
// val endX = textLine.textChars.lastOrNull()?.end ?: return
// if (endX > visibleRight) {
// val cc = (endX - visibleRight) / words.size
// for (i in 0..words.lastIndex) {
// textLine.getTextCharReverseAt(i).let {
// val py = cc * (words.size - i)
// it.start = it.start - py
// it.end = it.end - py
// }
// }
// }
}
/**
@ -529,7 +567,7 @@ object ChapterProvider {
if (width > 0 && height > 0 && (width != viewWidth || height != viewHeight)) {
viewWidth = width
viewHeight = height
isHorizontal = width > height
doublePage = width > height
upVisibleSize()
postEvent(EventBus.UP_CONFIG, true)
}
@ -542,13 +580,15 @@ object ChapterProvider {
if (viewWidth > 0 && viewHeight > 0) {
paddingLeft = ReadBookConfig.paddingLeft.dp
paddingTop = ReadBookConfig.paddingTop.dp
visibleWidth = if (isHorizontal) {
viewWidth / 2 - paddingLeft - ReadBookConfig.paddingRight.dp
paddingRight = ReadBookConfig.paddingRight.dp
paddingBottom = ReadBookConfig.paddingBottom.dp
visibleWidth = if (doublePage) {
viewWidth / 2 - paddingLeft - paddingRight
} else {
viewWidth - paddingLeft - ReadBookConfig.paddingRight.dp
viewWidth - paddingLeft - paddingRight
}
visibleHeight = viewHeight - paddingTop - ReadBookConfig.paddingBottom.dp
visibleRight = paddingLeft + visibleWidth
visibleHeight = viewHeight - paddingTop - paddingBottom
visibleRight = viewWidth - paddingRight
visibleBottom = paddingTop + visibleHeight
}
}

Loading…
Cancel
Save