bugfix: word break issue.

This commit is contained in:
cgspine
2022-03-04 17:25:20 +08:00
parent 93b51178b5
commit ea3a0d1660
7 changed files with 47 additions and 21 deletions
@@ -159,7 +159,7 @@ class QDQQFaceUsageFragment : BaseFragment() {
}
private fun initData() {
val textParser: TextParser = EmojiTextParser(QDQQFaceManager.getInstance())
val textParser: TextParser = EmojiTextParser(QDQQFaceManager.getInstance()) { true }
mMarqueeTypeView1!!.fadeWidth = QMUIDisplayHelper.dp2px(context, 40).toFloat()
mMarqueeTypeView1!!.textParser = textParser
mMarqueeTypeView1!!.text = "🙃🙃🙃🙃飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀飘呀这是一行很长很长[微笑][微笑][微笑][微笑]的文本,但是[微笑][微笑][微笑][微笑]只能单行显示"
@@ -17,7 +17,6 @@ package com.qmuiteam.qmui.type
import android.graphics.Canvas
import androidx.core.util.Pools
import com.qmuiteam.qmui.type.TypeEnvironment
import com.qmuiteam.qmui.type.element.BreakWordLineElement
import com.qmuiteam.qmui.type.element.Element
import com.qmuiteam.qmui.type.element.NextParagraphElement
@@ -86,7 +85,7 @@ class Line private constructor() {
}
}
fun handleWordBreak(environment: TypeEnvironment?, shouldHandleWordBreak: Boolean): List<Element>? {
fun handleWordBreak(environment: TypeEnvironment, shouldHandleWordBreak: Boolean): List<Element>? {
if (mElements.size == 0 || !shouldHandleWordBreak) {
return null
}
@@ -96,7 +95,8 @@ class Line private constructor() {
val back: MutableList<Element> = LinkedList()
if (last.wordPart == Element.WORD_PART_WHOLE) {
if (last.lineBreakType == Element.LINE_BREAK_TYPE_NOT_END ||
next != null && next.lineBreakType == Element.LINE_BREAK_TYPE_NOT_START) {
next != null && next.lineBreakType == Element.LINE_BREAK_TYPE_NOT_START
) {
mElements.removeAt(lastIndex)
back.add(last)
}
@@ -109,7 +109,7 @@ class Line private constructor() {
back.add(last)
mElements.removeAt(lastIndex)
lastIndex--
val min = Math.max(0, lastIndex - 30) // try 30 letter.
val min = 0.coerceAtLeast(lastIndex - environment.workBreakMaxTryLength)
var find = false
while (lastIndex > min) {
val el = mElements[lastIndex]
@@ -119,10 +119,17 @@ class Line private constructor() {
} else if (el.lineBreakType == Element.LINE_BREAK_WORD_BREAK_ALLOWED) {
// TODO what if environment had changed after break? the measure may be wrong
val b = BreakWordLineElement()
b.measure(environment!!)
add(b)
find = true
break
b.measure(environment)
val backWidth = back.sumOf { it.measureWidth }
if (backWidth >= b.measureWidth) {
find = true
add(b)
break
} else {
back.add(0, el)
mElements.removeAt(lastIndex)
lastIndex--
}
} else {
back.add(0, el)
mElements.removeAt(lastIndex)
@@ -139,7 +146,7 @@ class Line private constructor() {
return null
}
for (el in back) {
contentWidth = (contentWidth -el.measureWidth).toInt()
contentWidth -= el.measureWidth
}
return back
}
@@ -171,8 +178,9 @@ class Line private constructor() {
for (i in 1 until mElements.size) {
val el = mElements[i]
if (el.visible != Element.GONE &&
(el.wordPart == Element.WORD_PART_WHOLE ||
el.wordPart == Element.WORD_PART_START)) {
(el.wordPart == Element.WORD_PART_WHOLE ||
el.wordPart == Element.WORD_PART_START)
) {
ret++
}
}
@@ -209,7 +217,8 @@ class Line private constructor() {
for (i in mElements.indices) {
val el = mElements[i]
if (i > 0 && (el.wordPart == Element.WORD_PART_WHOLE
|| el.wordPart == Element.WORD_PART_START)) {
|| el.wordPart == Element.WORD_PART_START)
) {
x += addSpace
mElements[i - 1].nextGapWidth = addSpace
}
@@ -33,6 +33,7 @@ class LineLayout {
var moreUnderlineColor = Color.TRANSPARENT
var moreBgColor = 0
var moreUnderlineHeight = 0
var moreTextFixAtEnd: Boolean = true
var typeModel: TypeModel? = null
var shouldHandleWordBreak: Boolean = true
@@ -234,7 +235,12 @@ class LineLayout {
}
lastLine.layout(env, dropLastIfSpace, true)
if (moreElement != null) {
moreElement.x = lastLine.x + lastLine.widthLimit - moreElement.measureWidth
if(moreTextFixAtEnd){
moreElement.x = lastLine.x + lastLine.widthLimit - moreElement.measureWidth
}else{
moreElement.x = lastLine.contentWidth - moreElement.measureWidth
}
}
}
@@ -72,7 +72,7 @@ class TypeEnvironment {
private val mCustomProp: SparseArray<Any?> = SparseArray()
private val mStack = SparseArray<Stack<Any?>>()
val layoutExcludeAreas = arrayListOf<Rect>()
var workBreakMaxTryLength: Int = 10
var lineSpace = 0
@@ -22,7 +22,10 @@ import com.qmuiteam.qmui.type.element.NextParagraphElement
import com.qmuiteam.qmui.type.element.TextElement
import java.util.*
class EmojiTextParser(private val emojiProvider: EmojiResourceProvider) : TextParser {
class EmojiTextParser(
private val emojiProvider: EmojiResourceProvider,
private val wordBreakChecker: (c: Char) -> Boolean
) : TextParser {
override fun parse(text: CharSequence?): TypeModel? {
if(text == null || text.isEmpty()){
@@ -105,7 +108,7 @@ class EmojiTextParser(private val emojiProvider: EmojiResourceProvider) : TextPa
i += charCount - 1
}
}
ParserHelper.handleWordPart(c, last, tmp!!)
ParserHelper.handleWordPart(c, last, tmp!!, wordBreakChecker)
index++
if (first == null) {
first = tmp
@@ -23,16 +23,20 @@ object ParserHelper {
return c in 'a'..'z' || c in 'A'..'Z' || c in '0'..'9'
}
fun handleWordPart(c: Char, prev: Element?, curr: Element) {
fun handleWordPart(c: Char, prev: Element?, curr: Element, wordBreakChecker: (c: Char) -> Boolean) {
if (isEnglishLetterOrNumber(c)) {
if (prev == null || prev.wordPart == Element.WORD_PART_WHOLE || prev.wordPart == Element.WORD_PART_END) {
curr.wordPart = Element.WORD_PART_START
} else {
curr.wordPart = Element.WORD_PART_MIDDLE
if(wordBreakChecker(c)){
curr.lineBreakType = Element.LINE_BREAK_WORD_BREAK_ALLOWED
}
}
} else {
if (prev != null && prev.wordPart == Element.WORD_PART_MIDDLE) {
prev.wordPart = Element.WORD_PART_END
prev.lineBreakType = Element.LINE_BREAK_TYPE_NORMAL
}
curr.wordPart = Element.WORD_PART_WHOLE
}
@@ -22,11 +22,15 @@ import com.qmuiteam.qmui.type.element.TextElement
import com.qmuiteam.qmui.type.parser.ParserHelper.handleWordPart
import java.util.*
class PlainTextParser : TextParser {
class PlainTextParser(
private val wordBreakChecker: (c: Char) -> Boolean
) : TextParser {
companion object {
val instance by lazy {
PlainTextParser()
PlainTextParser {
false
}
}
}
@@ -58,7 +62,7 @@ class PlainTextParser : TextParser {
tmp = TextElement(text.subSequence(i, i + charCount), index, i)
i += charCount - 1
}
handleWordPart(c, last, tmp)
handleWordPart(c, last, tmp, wordBreakChecker)
index++
if (first == null) {
first = tmp