【问题标题】:Android TextView format multiple wordsAndroid TextView 格式化多个单词
【发布时间】:2012-04-02 09:18:37
【问题描述】:

原字符串:

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

格式化后:

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

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

代码

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;
}

【问题讨论】:

    标签: android spannablestring


    【解决方案1】:

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

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

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

    new ForegroundColorSpan(0xFF0099FF)
    

    当 span 对象存在于 spannableStringBuilder 中时,它只会改变边界,不会添加新的 span。

    【讨论】:

    • 嘿伙计们@pawelzieba 我知道这真的很旧,但我尝试了上面的代码,它仍然只格式化最后一个for (CharacterStyle c : cs) ssb.setSpan(c, start, end, 0);
    【解决方案2】:

    我会建议一种更简单的方法。如果您的格式化需求是基本的,一个简单的正则表达式 + Html.fromHtml() 应该可以解决问题:

    private void format() {
        String mText = editContent.getText();
    
        Spanned mSpannedText = Html.fromHtml(mText.replaceAll("##(.*?)##)","<font color=\"0xFF0099\">#$1</font>"), 
    
        editContent.setText(mSpannedText);
    }
    

    【讨论】:

    • 我认为 REGEX 和 WEBVIEWS 都是最后一个资源,它们都是资源密集型的,因此不适合简单的事情。
    • @Jorge Aguilar,我认为这个 sn-p 不会创建 web 视图。对性能的影响可以忽略不计。
    • @Sebastien 你说得对,sn-p 没有创建 webview,但你仍然使用 HTML 来处理问题,这带来了不需要的解析和其他处理,你可能是对的在一个小案例上性能影响并不大,但如果你在一个更大的例子上尝试它,差异就会开始显现。无论如何,并不是因为它可以“足够快”完成意味着您可以随意使用资源,优化总是一件好事。
    【解决方案3】:

    最终解决方案正确循环,但是您的第一个令牌不会像您使用的那样被正确删除

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

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

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

    这将确保您的文本得到正确编辑,并且您的标记的所有痕迹都被删除。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-13
      • 2020-04-28
      • 1970-01-01
      • 2017-04-19
      • 2013-07-28
      • 2016-12-15
      • 2014-08-01
      • 1970-01-01
      相关资源
      最近更新 更多