安卓截取字符串,TextView显示并颜色标记+点击事件
对字符串中的多个带标记的字段,进行标记,并赋予点击事件。难点在于你如何处理字符串。
废话少说,直接进入正题
场景
要解析的字符串示例:
String str = "请问你是要查询<s>无线告警</s>还是下面的这些告警信息呢?<br />*<s>传输告警</s><br />*<s>故障单告警</s>(仅支持AGZ工单)<br />*<s>割接单告警</s><br />";
要求:将以上字符串以文本的形式展示出来,其中<s></s>中间的内容需红色显示,且点击该字体时弹出该内容,<br />为换行符,进行换行。
结果大概就这个样子:
plan 1
思路:使用split(String str)方法分割字符串,获取每个需要标记的字符串的起始和结束的位置,再使用SpannableStringBuilder进行文字标记及点击事件的处理。
上代码
public class SpannableStringBuilderActivity extends AppCompatActivity {
private static final String TAG = "SpannableStringBuilderA";
// 用于截取快捷点击项
public static String INTERCEPT_START = "<s>";
public static String INTERCEPT_END = "</s>";
private String text = "请问你是要查询<s>无线告警</s>还是下面的这些告警信息呢?<br />*<s>传输告警</s><br />*<s>故障单告警</s>(仅支持AGZ工单)<br />*<s>割接单告警</s><br />";
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 布局就一个TextView
setContentView(R.layout.activity_spannable_string_builder);
initView();
}
private void initView() {
mTextView = findViewById(R.id.textView);
// 请不要问我为何不直接使用 \n, 源数据就是如此,当然如果后台愿意转义处理,请处理
text = text.replaceAll("<br />","\n");
// 这个方法是对字符串处理的核心,传入的第二个参数 如果你只有一个字符标记那就传一个字符
List<Point> pointList = getSpecialContentPointList(text, INTERCEPT_START + "|" + INTERCEPT_END);
SpannableStringBuilder spBuilder = new SpannableStringBuilder();
// 添加字符时要把标记去掉,原因去看字符串的处理
String showText = text.replaceAll(INTERCEPT_START,"");
showText = showText.replaceAll(INTERCEPT_END,"");
spBuilder.append(showText);
for (Point point : pointList){
// 添加颜色
spBuilder.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorAccent)), point.x, point.y,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
final CharSequence clickText = (spBuilder.subSequence(point.x, point.y));
// 点击事件
spBuilder.setSpan(new ClickableSpan() {
@Override
public void onClick(View widget) {
Log.i(TAG, "onClick: 你现在点击的是" + clickText);
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setColor(getResources().getColor(R.color.colorRed));
ds.setUnderlineText(false);
}
}, point.x, point.y, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
mTextView.setText(spBuilder);
// 这个必须加,否则点击事件不生效
mTextView.setMovementMethod(LinkMovementMethod.getInstance());
}
public static List<Point> getSpecialContentPointList(String content, String regex) {
List<Point> list = new ArrayList<>();
if (isNull(content)) {
return list;
}
if (isNull(regex)) {
list.add(new Point(0, content.length()));
return list;
}
String[] strs = content.split(regex);
int x = 0;
int y = 0;
for (int i = 0; i < strs.length; i++) {
Log.i(TAG, "getSpecialContentPointList: str = " + strs[i] );
if (i % 2 == 1) {
y = x + strs[i].length();
list.add(new Point(x, y));
x = x + strs[i].length();
} else {
x += strs[i].length();
}
}
return list;
}
}
plan 2
思路:截取字符串时,每次只处理截取之后剩余的字符串,然后遍历进行处理
plan3
思路:将需要标记的字符串,使用正则表达式截取出来变成一个List
后面两种抽空整理一下再写