feat: add isAutoRemeasureText in PanguTextConfig

This commit is contained in:
2025-02-11 15:55:00 +08:00
parent 9148d29f37
commit 7a233d82d8
6 changed files with 73 additions and 1 deletions

View File

@@ -272,6 +272,15 @@ config.isEnabled = true
// Processing Spanned text is enabled by default, but this feature is experimental.
// If issues occur, you can disable it. When disabled, Spanned text will return the original text.
config.isProcessedSpanned = true
// Whether to automatically re-measure the text width after processing.
// Note: [PanguText] after injecting text and changing the text,
// the width of [TextView] will not be calculated automatically.
// At this time, this feature will call [TextView.setText] to re-execute the measurements,
// which can fix every time in some dynamic layouts (such as `RecyclerView`) changes in text width,
// but may cause performance issues, you can choose to disable this feature.
// To prevent unnecessary performance overhead,
// this feature only takes effect on [TextView] with `maxLines` set to 1 or `singleLine`.
config.isAutoRemeasureText = true
// Set patterns to exclude during formatting using regular expressions.
// For example, exclude all URLs.
config.excludePatterns.add("https?://\\S+".toRegex())
@@ -319,6 +328,7 @@ If you integrated using the [Inject to LayoutInflater](#inject-to-layoutinflater
- `panguText_enabled` corresponds to `PanguTextConfig.isEnabled`
- `panguText_processedSpanned` corresponds to `PanguTextConfig.isProcessedSpanned`
- `panguText_autoRemeasureText` corresponds to `PanguTextConfig.isAutoRemeasureText`
- `panguText_excludePatterns` corresponds to `PanguTextConfig.excludePatterns`, string array, multiple patterns separated by `|@|`
- `panguText_cjkSpacingRatio` corresponds to `PanguTextConfig.cjkSpacingRatio`
@@ -332,6 +342,7 @@ If you integrated using the [Inject to LayoutInflater](#inject-to-layoutinflater
android:text="Xiaoming今年16岁"
app:panguText_enabled="true"
app:panguText_processedSpanned="true"
app:panguText_autoRemeasureText="true"
app:panguText_excludePatterns="https?://\\S+;\\[.*?]|@|\\[.*?]"
app:panguText_cjkSpacingRatio="7.0" />
```

View File

@@ -271,6 +271,13 @@ config.isEnabled = true
// Spanned 文本处理默认启用,但此功能尚处于实验性阶段,
// 如果发生问题你可以选择禁用,禁用后遇到 Spanned 文本将返回原始文本
config.isProcessedSpanned = true
// 是否要在处理后自动重新测量文本宽度
// 注意:[PanguText] 注入文本并更改文本后,[TextView] 的宽度将不会自动计算
// 目前,此功能将调用 [TextView.setText] 重新执行测量结果,
// 该测量可以在某些动态布局 (例如 `RecyclerView`) 中每次修复文本宽度,
// 但可能会导致性能问题,你可以选择禁用此功能
// 为了防止不必要的性能开销,此功能仅在 `maxlines` 设置为 1 或 `singleLine` 的 [TextView] 上生效
config.isAutoRemeasureText = true
// 设置在格式化过程中以正则形式定义需要排除的内容
// 例如排除全部 URL
config.excludePatterns.add("https?://\\S+".toRegex())
@@ -317,6 +324,7 @@ textView.injectPanguText(config = config2)
- `panguText_enabled` 对应 `PanguTextConfig.isEnabled`
- `panguText_processedSpanned` 对应 `PanguTextConfig.isProcessedSpanned`
- `panguText_autoRemeasureText` 对应 `PanguTextConfig.isAutoRemeasureText`
- `panguText_excludePatterns` 对应 `PanguTextConfig.excludePatterns`,字符串数组,多个使用 `|@|` 分隔
- `panguText_cjkSpacingRatio` 对应 `PanguTextConfig.cjkSpacingRatio`
@@ -330,6 +338,7 @@ textView.injectPanguText(config = config2)
android:text="Xiaoming今年16岁"
app:panguText_enabled="true"
app:panguText_processedSpanned="true"
app:panguText_autoRemeasureText="true"
app:panguText_excludePatterns="https?://\\S+;\\[.*?]|@|\\[.*?]"
app:panguText_cjkSpacingRatio="7.0" />
```

View File

@@ -22,6 +22,7 @@
package com.highcapable.pangutext.android
import android.text.Spanned
import android.widget.TextView
import java.io.Serializable
/**
@@ -53,6 +54,18 @@ class PanguTextConfig internal constructor() : Serializable {
*/
var isProcessedSpanned = true
/**
* Whether to automatically re-measure the text width after processing.
*
* - Note: [PanguText] after injecting text and changing the text,
* the width of [TextView] will not be calculated automatically.
* At this time, this feature will call [TextView.setText] to re-execute the measurements,
* which can fix every time in some dynamic layouts (such as `RecyclerView`) changes in text width,
* but may cause performance issues, you can choose to disable this feature.
* To prevent unnecessary performance overhead, this feature only takes effect on [TextView] with `maxLines` set to 1 or `singleLine`.
*/
var isAutoRemeasureText = true
/**
* The regular expression for text content that needs to be excluded.
* [PanguText] processing will be skipped after matching these texts.
@@ -87,6 +100,7 @@ class PanguTextConfig internal constructor() : Serializable {
fun copy(body: PanguTextConfig.() -> Unit = {}) = PanguTextConfig().also {
it.isEnabled = this.isEnabled
it.isProcessedSpanned = this.isProcessedSpanned
it.isAutoRemeasureText = this.isAutoRemeasureText
it.excludePatterns.addAll(this.excludePatterns)
it.cjkSpacingRatio = this.cjkSpacingRatio
it.body()

View File

@@ -23,10 +23,13 @@ package com.highcapable.pangutext.android.core
import android.text.Editable
import android.text.TextWatcher
import android.widget.EditText
import android.widget.TextView
import com.highcapable.betterandroid.system.extension.tool.SystemVersion
import com.highcapable.pangutext.android.PanguText
import com.highcapable.pangutext.android.PanguTextConfig
import com.highcapable.pangutext.android.extension.injectRealTimePanguText
import com.highcapable.yukireflection.factory.current
/**
* A [TextWatcher] that automatically applies [PanguText] to the text content.
@@ -36,8 +39,39 @@ import com.highcapable.pangutext.android.extension.injectRealTimePanguText
* @param config the configuration of [PanguText].
*/
class PanguTextWatcher internal constructor(private val base: TextView, private val config: PanguTextConfig) : TextWatcher {
/**
* The text watchers of the base [TextView].
* @return [ArrayList]<[TextWatcher]>.
*/
private val textWatchers
get() = base.current(ignored = true).field {
name = "mListeners"
superClass()
}.cast<ArrayList<TextWatcher>>()
/**
* Whether to automatically re-measure the text width after processing.
* @return [Boolean]
*/
private val isAutoRemeasureText
get() = config.isAutoRemeasureText && base !is EditText && (base.maxLines == 1 ||
SystemVersion.require(SystemVersion.Q, base.maxLines == 1) { base.isSingleLine })
override fun afterTextChanged(editable: Editable?) {
editable?.let { PanguText.format(base.resources, base.textSize, it, config) }
if (!isAutoRemeasureText) return
val currentWatchers = mutableListOf<TextWatcher>()
textWatchers?.also {
currentWatchers.addAll(it)
// Avoid triggering events again during processing.
it.clear()
}
// Reset the text to trigger remeasurement.
base.text = editable
// Re-add to continue listening to text changes.
textWatchers?.addAll(currentWatchers)
currentWatchers.clear()
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}

View File

@@ -87,6 +87,7 @@ internal object PanguWidget {
} else instance.obtainStyledAttributes(attrs, R.styleable.PanguTextHelper) {
val isEnabled = it.getBooleanOrNull(R.styleable.PanguTextHelper_panguText_enabled)
val isProcessedSpanned = it.getBooleanOrNull(R.styleable.PanguTextHelper_panguText_processedSpanned)
val isAutoRemeasureText = it.getBooleanOrNull(R.styleable.PanguTextHelper_panguText_autoRemeasureText)
val cjkSpacingRatio = it.getFloatOrNull(R.styleable.PanguTextHelper_panguText_cjkSpacingRatio)
val excludePatterns = it.getStringOrNull(R.styleable.PanguTextHelper_panguText_excludePatterns)
?.split(TEXT_REGEX_SPLITE_SYMBOL)?.mapNotNull { regex ->
@@ -95,9 +96,10 @@ internal object PanguWidget {
}.getOrNull()
}?.toTypedArray() ?: emptyArray()
if (isEnabled == false) return instance
if (isProcessedSpanned != null || cjkSpacingRatio != null || excludePatterns.isNotEmpty()) {
if (isProcessedSpanned != null || isAutoRemeasureText != null || cjkSpacingRatio != null || excludePatterns.isNotEmpty()) {
val configCopy = config.copy()
configCopy.isProcessedSpanned = isProcessedSpanned ?: config.isProcessedSpanned
configCopy.isAutoRemeasureText = isAutoRemeasureText ?: config.isAutoRemeasureText
configCopy.cjkSpacingRatio = cjkSpacingRatio ?: config.cjkSpacingRatio
if (excludePatterns.isNotEmpty()) {
config.excludePatterns.clear()

View File

@@ -5,6 +5,8 @@
<attr name="panguText_enabled" format="boolean" />
<!-- Processed [Spanned] text (experimental). -->
<attr name="panguText_processedSpanned" format="boolean" />
<!-- Whether to automatically re-measure the text width after processing. -->
<attr name="panguText_autoRemeasureText" format="boolean" />
<!-- The regular expression for text content that needs to be excluded. -->
<attr name="panguText_excludePatterns" format="string" />
<!-- The CJK spacing ratio. -->