与接受的答案类似,我尝试为此编写 Kotlin 扩展方法。
这是 Kotlin 中公认的答案
@Suppress("DEPRECATION")
fun Context.getText(id: Int, vararg args: Any): CharSequence {
val escapedArgs = args.map {
if (it is String) TextUtils.htmlEncode(it) else it
}.toTypedArray()
return Html.fromHtml(String.format(Html.toHtml(SpannedString(getText(id))), *escapedArgs))
}
已接受答案的问题在于,当格式参数本身被设置样式(即跨区,而不是字符串)时,它似乎不起作用。通过实验,它似乎做了一些奇怪的事情,可能与我们没有转义非字符串 CharSequences 的事实有关。如果我打电话,我会看到
context.getText(R.id.my_format_string, myHelloSpanned)
其中 R.id.my_format_string 是:
<string name="my_format_string">===%1$s===</string>
myHelloSpanned 是一个看起来像 hello 的 Spanned(即它会有 HTML <i>&lt;b&gt;hello&lt;/b&gt;</i>)然后我得到 ===hello ===(即 HTML ===<b>hello</b>===)。
错了,我应该得到 ===hello===。
我尝试通过在应用 String.format 之前将所有 CharSequence 转换为 HTML 来解决此问题,这是我的结果代码。
@Suppress("DEPRECATION")
fun Context.getText(@StringRes resId: Int, vararg formatArgs: Any): CharSequence {
// First, convert any styled Spanned back to HTML strings before applying String.format. This
// converts the styling to HTML and also does HTML escaping.
// For other CharSequences, just do HTML escaping.
// (Leave any other args alone.)
val htmlFormatArgs = formatArgs.map {
if (it is Spanned) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.toHtml(it, Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE)
} else {
Html.toHtml(it)
}
} else if (it is CharSequence) {
Html.escapeHtml(it)
} else {
it
}
}.toTypedArray()
// Next, get the format string, and do the same to that.
val formatString = getText(resId);
val htmlFormatString = if (formatString is Spanned) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.toHtml(formatString, Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE)
} else {
Html.toHtml(formatString)
}
} else {
Html.escapeHtml(formatString)
}
// Now apply the String.format
val htmlResultString = String.format(htmlFormatString, *htmlFormatArgs)
// Convert back to a CharSequence, recovering any of the HTML styling.
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(htmlResultString, Html.FROM_HTML_MODE_LEGACY)
} else {
Html.fromHtml(htmlResultString)
}
}
但是,这并不太奏效,因为当您调用 Html.toHtml 时,它会将 <p> 标记放在所有内容周围,即使输入中没有额外的填充。换句话说,Html.fromHtml(Html.toHtml(myHelloSpanned)) 不等于 myHelloSpanned - 它有额外的填充。我不知道如何很好地解决这个问题。