使用SpannableStringBuilder注意事项
需求中有一行文字显示的大小、颜色、下划线、加粗等不同,可以用几个TextView实现,也可以用SpannableStringBuilder在一个TextView上实现,还可以在string的文件中用H5的语法写。
后两种的差别主要在点击事件上,用H5的语法没法对一个字符串中的几个字设置点击事件。
使用时把多个字符串用append()方法拼接上,设置需要用到的Span。
- 设置Span时要注意按照顺序
- 设置颜色、点击事件时Span对象不能复用,用几个就要创建几个
- 对ClickableSpan默认有下划线,可以重写updateDrawState方法去掉
- 用ClickableSpan时,除了用setText,还要用lawAndPrivacyTv.setMovementMethod(LinkMovementMethod.getInstance())否则点击事件不生效
- 另,重写的updateDrawState方法里也可以设置默认颜色(setColor)
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
:前后都不包括,即在指定范围的前面和后面插入新字符都不会应用新样式
Spannable.SPAN_EXCLUSIVE_INCLUSIVE
:前面不包括,后面包括。即仅在范围字符的后面插入新字符时会应用新样式
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
:前面包括,后面不包括。
Spannable.SPAN_INCLUSIVE_INCLUSIVE
:前后都包括。
源码:
private void initLawAndPrivacyTv() {
int position = 0;
String agree = Utils.getString(R.string.text_agree);
String privacy = Utils.getString(R.string.privacy_policy);
String and = Utils.getString(R.string.text_and);
String law = Utils.getString(R.string.law_policy);
ForegroundColorSpan agreeBlackSpan = new ForegroundColorSpan(Color.BLACK);
ForegroundColorSpan andBlackSpan = new ForegroundColorSpan(Color.BLACK);
ForegroundColorSpan privacyBlueSpan = new ForegroundColorSpan(Utils.getColor(R.color.color_3091F2));
ForegroundColorSpan lawBlueSpan = new ForegroundColorSpan(Utils.getColor(R.color.color_3091F2));
ClickableSpan privacyClickableSpan = new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
jumpToPrivacyPolicy();
}
@Override
public void updateDrawState(@NonNull TextPaint textPaint) {
super.updateDrawState(textPaint);
textPaint.setUnderlineText(false);
}
};
ClickableSpan lawClickableSpan = new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
JumpToLawPolicy();
}
@Override
public void updateDrawState(@NonNull TextPaint textPaint) {
super.updateDrawState(textPaint);
textPaint.setUnderlineText(false);
}
};
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
stringBuilder.append(agree);
stringBuilder.setSpan(agreeBlackSpan, 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
position += agree.length();
stringBuilder.append(law);
stringBuilder.setSpan(lawBlueSpan, position, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
stringBuilder.setSpan(lawClickableSpan, position, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
position += law.length();
stringBuilder.append(and);
stringBuilder.setSpan(andBlackSpan, position, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
position += and.length();
stringBuilder.append(privacy);
stringBuilder.setSpan(privacyBlueSpan, position, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
stringBuilder.setSpan(privacyClickableSpan, position, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
lawAndPrivacyTv.setText(stringBuilder);
// 不设置点击事件不起作用
lawAndPrivacyTv.setMovementMethod(LinkMovementMethod.getInstance());
}
除了SpannableStringBuilder,还有个SpannableString,区别和String与StringBuilder的区别相同。
补充:
四种flag在按照顺序拼接文字时没有区别,区别在SpannableStringBuilder#insert
时,如下(x为增加的):
SPAN_INCLUSIVE_INCLUSIVE
SPAN_INCLUSIVE_EXCLUSIVE
SPAN_EXCLUSIVE_INCLUSIVE
SPAN_EXCLUSIVE_EXCLUSIVE
Java代码:
String myString ="01234";
int start = 1;
int end = 3;
int spanFlag = Spannable.SPAN_INCLUSIVE_INCLUSIVE; // this is what is changing
// set the span
SpannableStringBuilder spannableString = new SpannableStringBuilder(myString);
ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED);
spannableString.setSpan(foregroundSpan, start, end, spanFlag);
// insert the text after the span has already been set
// (inserting at start index second so that end index doesn't get messed up)
spannableString.insert(end,"x");
spannableString.insert(start,"x");
textView.setText(spannableString);