首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spannable与String.format()的结合

Spannable与String.format()的结合
EN

Stack Overflow用户
提问于 2014-01-05 17:41:29
回答 5查看 12.2K关注 0票数 31

假设您有以下字符串:

代码语言:javascript
复制
String s = "The cold hand reaches for the %1$s %2$s Ellesse's";
String old = "old"; 
String tan = "tan"; 
String formatted = String.format(s,old,tan); //"The cold hand reaches for the old tan Ellesse's"

假设您希望以这个字符串结束,但也要为任何单词设置一个特定的Span,由String.format替换。

例如,我们还想做以下工作:

代码语言:javascript
复制
Spannable spannable = new SpannableString(formatted);
spannable.setSpan(new StrikethroughSpan(), oldStart, oldStart+old.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new ForegroundColorSpan(Color.BLUE), tanStart, tanStart+tan.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

是否有可靠的方法来了解oldtan的起始指数?

请注意,只要搜索“old”,就会在“冷”中返回“old”,这样就不起作用了。

我猜,有效的方法是事先搜索%[0-9]$s,并计算String.format中的替换项的偏移量。不过,这似乎是一个令人头痛的问题,我怀疑可能会有一种类似于String.format的方法,它可以提供更多关于其格式细节的信息。嗯,有吗?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2014-01-05 18:35:31

像这样使用Spannable是一个令人头痛的问题--这可能是最直接的方法:

代码语言:javascript
复制
String s = "The cold hand reaches for the %1$s %2$s Ellesse's";
String old = "<font color=\"blue\">old</font>"; 
String tan = "<strike>tan</strike>"; 
String formatted = String.format(s,old,tan); //The cold hand reaches for the <font color="blue">old</font> <strike>tan</strike> Ellesse's

Spannable spannable = Html.fromHtml(formatted);

问题:这不包含在StrikethroughSpan中。为了制作StrikethroughSpan,我们从这个问题那里借用了一个定制的TagHandler

代码语言:javascript
复制
Spannable spannable = Html.fromHtml(text,null,new MyHtmlTagHandler());

MyTagHandler:

代码语言:javascript
复制
public class MyHtmlTagHandler implements Html.TagHandler {
    public void handleTag(boolean opening, String tag, Editable output,
                          XMLReader xmlReader) {
        if (tag.equalsIgnoreCase("strike") || tag.equals("s")) {
            processStrike(opening, output);
        }
    }
    private void processStrike(boolean opening, Editable output) {
        int len = output.length();
        if (opening) {
            output.setSpan(new StrikethroughSpan(), len, len, Spannable.SPAN_MARK_MARK);
        } else {
            Object obj = getLast(output, StrikethroughSpan.class);
            int where = output.getSpanStart(obj);
            output.removeSpan(obj);
            if (where != len) {
                output.setSpan(new StrikethroughSpan(), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    }

    private Object getLast(Editable text, Class kind) {
        Object[] objs = text.getSpans(0, text.length(), kind);
        if (objs.length == 0) {
            return null;
        } else {
            for (int i = objs.length; i > 0; i--) {
                if (text.getSpanFlags(objs[i - 1]) == Spannable.SPAN_MARK_MARK) {
                    return objs[i - 1];
                }
            }
            return null;
        }
    }
}
票数 15
EN

Stack Overflow用户

发布于 2014-11-30 07:13:31

我已经创建了使用可扩展的String.format。下载并使用它,就像正常版本一样。在您的例子中,您将在格式说明符周围放置跨度(可能使用strings.xml)。在输出中,无论那些说明符被替换为什么,它们都会出现。

票数 17
EN

Stack Overflow用户

发布于 2019-06-14 13:25:31

我制作了简单的Kotlin扩展函数,可以解决String.format跨范围的问题:

代码语言:javascript
复制
fun Context.getStringSpanned(@StringRes resId: Int, vararg formatArgs: Any): Spanned {
    var lastArgIndex = 0
    val spannableStringBuilder = SpannableStringBuilder(getString(resId, *formatArgs))
    for (arg in formatArgs) {
        val argString = arg.toString()
        lastArgIndex = spannableStringBuilder.indexOf(argString, lastArgIndex)
        if (lastArgIndex != -1) {
            (arg as? CharSequence)?.let {
                spannableStringBuilder.replace(lastArgIndex, lastArgIndex + argString.length, it)
            }
            lastArgIndex += argString.length
        }
    }

    return spannableStringBuilder
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20936901

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档