setText(CharSequence text, BufferType type)
TextView.setText()
有两个重载方法用于设置文本内容:
//TextView.java
private BufferType mBufferType = BufferType.NORMAL;
//1
public final void setText(CharSequence text) {
setText(text, mBufferType); //mBufferType默许是BufferType.NORMAL类型
}
//2
public void setText(CharSequence text, BufferType type) {
.......
}
public enum BufferType {
NORMAL, SPANNABLE, EDITABLE
}
setText(CharSequence text)
最终也是调用了setText(CharSequence text, BufferType type)
方法将 text
设置为 TextView
的文本内容,并运用指定的 BufferType
类型来处理文本。
依据不同的类型,TextView
会采取不同的方法处理文本内容。两个参数的意义:
-
text:
CharSequence
类型,可所以字符串或其他CharSequence
的完成类。 -
type:文本的处理类型,类型为
BufferType
枚举,可选值为NORMAL
、SPANNABLE
或EDITABLE
。
BufferType
枚举类型包括以下三个常量:
-
NORMAL
:表明普通文本类型,不支撑任何款式或作用,默许设置。 -
SPANNABLE
:表明可运用插入Span
的文本类型,能够运用Spannable
或其子类(如SpannableString
、SpannableStringBuilder
)来设置文本的款式和作用,例如色彩、字体、点击事情等。 -
EDITABLE
:表明可修正的文本类型,用于EditTextView
中。
示例:
TextView textView = findViewById(R.id.textView);
// 1、运用默许的 BufferType.NORMAL 处理文本
textView.setText("Hello, World!");
// 2、运用 BufferType.SPANNABLE 处理文本,支撑设置款式和作用
SpannableString spannableString = new SpannableString("Hello, World!");
spannableString.setSpan(new ForegroundColorSpan(Color.RED), 0, 5, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString, TextView.BufferType.SPANNABLE);
// 假如setText被以BufferType.SPANNABLE方法调用,那么文字可被转为 Spannable:
val spannableText = textView.text as Spannable
// 现在咱们能够继续设置或删除 span
spannableText.setSpan(
ForegroundColorSpan(color),
0, 5, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
// 3、运用 BufferType.EDITABLE 处理文本,支撑修正功能
Editable editable = Editable.Factory.getInstance().newEditable("Editable text");
textView.setText(editable, TextView.BufferType.EDITABLE);
下面主要介绍BufferType.SPANNABLE
在设置Span
时的一些优化建议。
官方推荐运用Span的最佳做法
已知SpannedString 完成的 Spanned接口,SpannableString、SpannableStringBuilder 完成的 Spannable接口,而他们又都承继了CharSequence接口,如下:
在 TextView
中设置文本时能够依据不同需求选用多种节省内存的方法。
1、不更改文本,只附加或别离 Span
TextView.setText()
包括能够以不同方法处理 Span
的多种重载。例如,能够运用以下代码设置 Spannable
文本目标:
textView.setText(spannableObject)
调用此 setText()
重载时,TextView
会创立 Spannable
的副本作为 SpannedString
,并将其作为 CharSequence
保存在内存中。这意味着文本和 Span
都不可变,因此当需求更新文本或 Span
时,需求创立一个新的 Spannable
目标并再次调用 setText()
,而这也会触发从头丈量和从头绘制布局。
如需表明这些 Span
可变,您能够改为运用 setText(CharSequence text, TextView.BufferType type)
,如下例所示:
textView.setText(spannable, BufferType.SPANNABLE)
//将textView.text从头转变为Spannable
val spannableText = textView.text as Spannable
spannableText.setSpan(
ForegroundColorSpan(color),
8, spannableText.length,
SPAN_INCLUSIVE_INCLUSIVE
)
在该示例中,由于运用了 BufferType.SPANNABLE
参数,TextView
创立了 SpannableString
(留意这里不是SpannedString哟),而由 TextView
保存的 CharSequence
目标现在具有可变Span
标记和不可变文本。如需更新 Span
,咱们能够将该文本作为 Spannable
进行检索,然后依据需求更新 Span
。
当附加、别离或从头定位 Span
时,TextView
会自动更新以反映对文本的更改。不过请留意:假如更改现有 Span
的内部特点,还需求调用 invalidate()
(假如进行与外观相关的更改)或 requestLayout()
(假如进行与丈量相关的更改)。
2、在TextView 中多次设置文本
在某些情况下(例如运用 RecyclerView.ViewHolder
时),可能想要重复运用 TextView
并多次设置文本。默许情况下,不管是否设置 BufferType
,TextView
都会创立 CharSequence
目标的副本并将其保存在内存中,这意味着每次设置新的文本时,TextView
都会创立一个新目标。
假如希望更好地操控此进程并避免创立额外的目标,能够完成自己的 Spannable.Factory
并替换 newSpannable()
。能够不用创立新的文本目标,而直接对现有 CharSequence
进行类型转化并将其作为 Spannable
返回,如下所示:
//默许的Spannable.Factory
public static class Factory {
private static Spannable.Factory sInstance = new Spannable.Factory();
/**
* Returns the standard Spannable Factory.
*/
public static Spannable.Factory getInstance() {
return sInstance;
}
/**
* Returns a new SpannableString from the specified CharSequence.
* You can override this to provide a different kind of Spannable.
*/
public Spannable newSpannable(CharSequence source) {
return new SpannableString(source);
}
}
//自定义Spannable.Factory
val spannableFactory = object : Spannable.Factory() {
override fun newSpannable(source: CharSequence?): Spannable {
return source as Spannable
}
}
请留意,在设置文本时,必须运用 textView.setText(spannableObject, BufferType.SPANNABLE)
。不然,源 CharSequence
将作为 Spanned
实例进行创立,并且无法转化为 Spannable
,然后导致 newSpannable()
抛出 ClassCastException
。
在替换 newSpannable()
之后,需求告知 TextView
运用新的 Factory
:
textView.setSpannableFactory(spannableFactory)
请必须在取得对 TextView
的引用后立即设置 Spannable.Factory
目标。假如运用的是 RecyclerView
,请在初次创立视图时设置 Factory
目标。这可避免 RecyclerView
在将新的项绑定到 ViewHolder
时创立额外的目标。
3、更改内部 Span 特点
假如只需更改可变 Span
的内部特点(例如,自定义项目符号 Span
中的项目符号色彩),能够经过在创立 Span
时保存对该 Span
的引用来避免多次调用 setText()
所产生的开支。当需求修正 Span
时,能够修正引用,然后依据更改的特点类型,对 TextView
调用 invalidate()
或 requestLayout()
。
在下面的代码示例中,自定义项目符号完成的默许色彩为红色,在点击按钮时会变为灰色:
class MainActivity : AppCompatActivity() {
// keeping the span as a field
val bulletSpan = BulletPointSpan(color = Color.RED)
override fun onCreate(savedInstanceState: Bundle?) {
...
val spannable = SpannableString("Text is spantastic")
// setting the span to the bulletSpan field
spannable.setSpan(
bulletSpan,
0, 4,
Spanned.SPAN_INCLUSIVE_INCLUSIVE
)
styledText.setText(spannable)
button.setOnClickListener {
// change the color of our mutable span
bulletSpan.color = Color.GRAY
// color won’t be changed until invalidate is called
styledText.invalidate()
}
}
}
材料
【1】https://developer.android.com/guide/topics/text/spans?hl=zh-cn#best-practices