HTML 태그를 사용하여 Android xml에서 직접 동적 문자열 스타일을 설정합니다.
CharSequences
을 사용해야 한다.예를 들어 안드로이드 자원 상자에서 xml을 정의할 수 있습니다<string name="lorem_ipsum">
This is <font color="red">red</font> and this
<b><i>bold and italic (nested); </i>this just bold</b>,
<u>underlined</u>
</string>
그리고 호출 CharSequence
을 통해 하나의 context.getText(stringRes: Int)
로 해석됩니다. 지원되는 모든 HTML 태그를 사용해서 텍스트 스타일을 설정합니다. 우리가 다른 일을 할 필요가 없습니다.그러나 때때로 우리는 문자열의 일부분을 동적으로 구축해야 한다.이를 위해 우리는
%{digit}${type}
형식의 자리 차지 문자로 xml의 동적 부분을 표시해야 한다. 예를 들어 %1$s
는 첫 번째 vararg로 전달되는 문자열이고 %2$d
는 두 번째 vararg로 전달되는 십진수String.format(text: String, vararg args: String)
로 자리 차지 문자를 해석한다.그러나 만약 우리가 이 예에서 복잡한 xml 자리 차지 문자를 사용하여 일부 물건을 정의한다면, 예를 들어 xml 자리 차지 문자
<string name="lorem_ipsum">
This is <font color="red">red</font> and this
<b><i>bold and italic (nested); </i>this just bold</b>, <u>underlined</u>
and here the placeholder = %1s
</string>
만약 우리가 String.format(text: String, vararg args: String)
의 방법 서명을 보았다면, 첫 번째 인자는 CharSequence
가 아니라 문자열이 필요합니다.이것은 동적 텍스트 자리 차지 문자가 정확하게 바뀌지만, 우리의 CharSequence
는 String
로 바뀌어 스타일을 포기해야 한다는 것을 의미한다.HTML 태그를 처리하기 위해 안드로이드는 HtmlCompat을 제공합니다.이것은 문자열 자원으로 시작하는 안전하지 않은 문자를 인코딩해야 한다. 즉,
'<'
, 즉 '<'
<string name="lorem_ipsum">
This is <font color="red">red</font>
and this <b><i>bold and italic (nested); </i>this just bold</b>,
<u>underlined</u> and here the placeholder = %1s
</string>
또는 리소스html tags를 다음과 같이 xml로 포장할 수 있습니다.<string name="lorem_ipsum">
<![CDATA[This is <font color="red">red</font> and this <b><i>bold and italic (nested); </i>this just bold</b>, <u>underlined</u> and here the placeholder = %1s]]>
</string>
어떠한 경우에도 동적 자리 표시자 텍스트가 자리 표시자 1이라고 가정하면 다음과 같이 HtmlCompat을 사용하여 예상 결과를 얻을 수 있습니다.val text = context.getString(R.string.lorem_ipsum)
val dynamicText = String.format(text, "placeholder1")
val dynamicStyledText = HtmlCompat.fromHtml(
dynamicText,
HtmlCompat.FROM_HTML_MODE_COMPACT
)
textView.text = dynamicStyledText
CDATASections 비록 위의 코드가 잘 작동하는 것 같지만 동적 자리 차지 문자 텍스트에 최소한 전의 없는 HTML 문자가 포함되어 있다면
<
, >
, &
, \
또는 "
는 결과가 달라질 것이다. 예를 들어 <placeholder1>
.네, 자리 표시자가 사라졌어요.이것은
HtmlCompat.fromHtml()
호출하기 전에 문자를 전의해야 하기 때문이다.HtmlCompat 를 사용하기 전에 자리 표시자를 인코딩하여 이 문제를 해결합니다. 아래와 같습니다.val text = context.getString(R.string.lorem_ipsum)
val encodedPlaceholder = TextUtils.htmlEncode("<placeholder1>")
val dynamicText = String.format(text, encodedPlaceholder)
val dynamicStyledText = HtmlCompat.fromHtml(
dynamicText,
HtmlCompat.FROM_HTML_MODE_COMPACT
)
textView.text = dynamicStyledText
비록 그것은 효과적이며 에 의해 추천된 방법이지만 나는 개인적으로 이전의 어떤 방법도 좋아하지 않는다.왜?
더 좋은 방법은 HTML 태그와 자리 표시자가 있는 원시 xml 문자열 자원을 처리하는 방법을 만드는 것입니다.이렇게 하면 문자열 자원에 HTML 태그가 포함되어 있든 없든 간에 이 방법은 자리 차지 문자를 처리하고 (기존, 있을 경우) HTML 태그로 정의된 스타일을 유지합니다.처음에 안전하지 않은 문자를 바꾸거나 추가할 필요가 없습니다.
네, 약간의 해커 기술이 가능합니다.어떠신지 한번 봅시다.
CDATA 섹션 더 나은 해결 방안을 찾다
context.getText(R.string.lorem_ipsum)
로 되돌아오는 문자열 자원 양식은 CharSequence
인 것으로 알고 있습니다.문자열 자원에 자리 차지 문자가 있으면 xml과 같은 방식으로 표시됩니다.또한 "일부"HTML 태그를 처리하는 방법
HtmlCompat.fromHtml()
도 알고 있습니다.그것의 역방법은 존재하고 정반대이다. Spanned
대상을 가져와 HTML 표시가 있는 문자열로 변환한다.우리가 이 방법에 전달한 표지도 매우 중요하다. HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL
HTML 문자열의 끝에 새 줄을 추가했기 때문에 우리는 이것에 대해 설명을 해야 한다.따라서 우리는 다음과 같이 필요한 HTML 문자열을 얻을 수 있다// step 2 - toHtml()
val spannedString = SpannedString(styledString)
val htmlString = HtmlCompat.toHtml(
spannedString,
HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL
)
.substringBeforeLast('>')
.plus(">")
이로 인해지금까지 첫 번째 단계의 스타일 문자열과 같은 HTML 문자열을 받았습니다.그러나 최종 목표는 해당 값으로 자리 차지 문자를 대체하는 것이다.내가 문장 첫머리에 언급한 바와 같이 우리는
String.format(text: String, vararg args: String)
로 이 점을 실현할 수 있다는 것을 기억할 수 있다.이것은 CharSequence
에 적용되지 않지만, 이것이 바로 우리가 먼저 그것을 같은 HTML 문자열로 변환하는 이유입니다.// step 3 - String.format()
val dynamicHtmlString = String.format(htmlString, args)
HTML 텍스트를 문자열로 변환하기만 하면 필요한 스타일을 얻을 수 있습니다.기억하고 사용하세요
HtmlCompat.FROM_HTML_MODE_COMPACT
. 왜냐하면 이것은 우리가 이전에 사용했던 HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL
와 상반되기 때문입니다.// step 4 - fromHtml()
val result = HtmlCompat.fromHtml(
dynamicStyledString,
HtmlCompat.FROM_HTML_MODE_COMPACT
)
.removeSuffix("\n") // fromHtml() adds a new line at the end
자, 우리 거의 다 완성했어...본문에서 보듯이 자리 차지 문자
Strings
가 안전하지 않은 문자를 포함하면 나타나지 않습니다.따라서, 자리 차지 문자를 바꾸기 위해 문자열 값을 인코딩해야 한다는 것을 잊지 마십시오.위의 모든 단계를 따르는 Kotlin 확장 함수는 다음과 같습니다.fun Context.getHtmlStyledText(
@StringRes htmlStringRes: Int,
vararg args: Any
): CharSequence {
// step 0 - Encode string placeholders
val escapedArgs = args.map {
if (it is String) TextUtils.htmlEncode(it) else it
}.toTypedArray()
// step 1 - getText()
val styledString = Context.getText(htmlStringRes)
// step 2 - toHtml()
val spannedString = SpannedString(styledString)
val htmlString = HtmlCompat.toHtml(
spannedString,
HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL
)
.substringBeforeLast('>')
.plus(">")
// step 3 - String.format()
val dynamicStyledString = String.format(htmlString, *escapedArgs)
// step 4 - fromHtml()
return HtmlCompat.fromHtml(
dynamicStyledString,
HtmlCompat.FROM_HTML_MODE_COMPACT
)
.removeSuffix("\n") //fromHtml() adds one new line at the end
}
보너스
같은 생각도 다원자원에 적용된다.간단히 바꾸다
// step 1 - getText()
val styledString = context.getText(R.string.lorem_ipsum)
가지다// step 1 - getText()
val styledString = context.resources.getQuantityText(R.plural.lorem_ipsum, quantity)
적절한
를 찾으실 수 있습니다.표지 사진 작성자working gist for strings and plurals here가 Markus Spiske
Reference
이 문제에 관하여(HTML 태그를 사용하여 Android xml에서 직접 동적 문자열 스타일을 설정합니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/sergiosastre/hi-3k6i텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)