mirror of
https://github.com/BetterAndroid/PanguText.git
synced 2025-09-01 08:15:21 +08:00
feat: add isAutoRemeasureText in PanguTextConfig
This commit is contained in:
@@ -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" />
|
||||
```
|
||||
|
@@ -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" />
|
||||
```
|
||||
|
@@ -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()
|
||||
|
@@ -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) {}
|
||||
|
@@ -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()
|
||||
|
@@ -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. -->
|
||||
|
Reference in New Issue
Block a user