Android TextView格式多个单词

时间:2012-04-02 09:18:38

标签: android spannablestring

原始字符串:

Lorem ## ipsum ## dolar ## sit ## atem。 Lorem ipsum dolar坐## atem ##。

格式化后:

Lorem #ipsum dolar #sit atem。 Lorem ipsum dolar坐#atem。

但只有最后一个有我想要的Formating。见下图。

CODE

private void format() {
    CharSequence text = editContent.getText();

    MovementMethod movementMethod = editContent.getMovementMethod();
    if ((movementMethod == null) || !(movementMethod instanceof LinkMovementMethod))
    {
        editContent.setMovementMethod(LinkMovementMethod.getInstance());
    }

    text = setSpanBetweenTokens(text, "##", new ForegroundColorSpan(0xFF0099FF), new UnderlineSpan(), new ClickableSpan() {
        @Override
        public void onClick(View widget) {
            Toast.makeText(getApplicationContext(), "click", Toast.LENGTH_SHORT).show();
        }
    });

    editContent.setText(text);
}

private static CharSequence setSpanBetweenTokens(CharSequence text, String token, CharacterStyle... characterStyle) {
    int tokenLen = token.length();
    int start = text.toString().indexOf(token) + 1;
    int end = text.toString().indexOf(token, start);

    while (start > -1 && end > -1)
    {
        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text);
        for (CharacterStyle c : characterStyle) {
            spannableStringBuilder.setSpan(c, start, end, 0);
        }

        spannableStringBuilder.delete(end, end + tokenLen);
        spannableStringBuilder.delete(start - 1, start);

        text = spannableStringBuilder;

        start = text.toString().indexOf(token) + 1;
        end = text.toString().indexOf(token, start);
    }

    return text;
}

修改

我的最终解决方案

private void format() {
    CharSequence text = editContent.getText();

    MovementMethod movementMethod = editContent.getMovementMethod();
    if ((movementMethod == null) || !(movementMethod instanceof LinkMovementMethod))
    {
        editContent.setMovementMethod(LinkMovementMethod.getInstance());
    }

    text = setSpanBetweenTokens(text, "##");

    editContent.setText(text);
}

private static CharSequence setSpanBetweenTokens(CharSequence text, String token) {
    int tokenLen = token.length();
    int start = text.toString().indexOf(token) + 1;
    int end = text.toString().indexOf(token, start);

    while (start > -1 && end > -1)
    {
        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text);

        spannableStringBuilder.setSpan(new ForegroundColorSpan(0xFF0099FF), start, end, 0);
        spannableStringBuilder.setSpan(new UnderlineSpan(), start, end, 0);
        spannableStringBuilder.setSpan(new ClickableSpan() {
            @Override
            public void onClick(View widget) {
                Log.d("DEBUG", "Click");
            }
        }, start, end, 0);

        spannableStringBuilder.delete(end, end + tokenLen);
        spannableStringBuilder.delete(start - 1, start);

        text = spannableStringBuilder;

        start = text.toString().indexOf(token) + 1;
        end = text.toString().indexOf(token, start);
    }

    return text;
}

3 个答案:

答案 0 :(得分:4)

为每个跨度传递不同的对象:

spannableStringBuilder.setSpan(c, start, end, 0);

您为每个范围传递相同的对象:

new ForegroundColorSpan(0xFF0099FF)

当spannableStringBuilder中存在span对象时,它只更改边界,而不是添加新的span。

答案 1 :(得分:3)

我建议采用更简单的方法。如果你的格式需求是基本的,一个简单的正则表达式+ Html.fromHtml()应该可以做到这一点:

private void format() {
    String mText = editContent.getText();

    Spanned mSpannedText = Html.fromHtml(mText.replaceAll("##(.*?)##)","<font color=\"0xFF0099\">#$1</font>"), 

    editContent.setText(mSpannedText);
}

答案 2 :(得分:1)

最终解决方案正确循环,但是您使用

时,第一个令牌将无法正确删除
int start = text.toString().indexOf(token) + 1;

仅当您的令牌长度为1个字符时才有效。由于您选择的令牌是##,因此更改上述代码以使用已创建的变量tokenLen

int start = text.toString().indexOf(token) + tokenLen;

这将确保正确编辑您的文本并删除所有令牌的痕迹。