HTML 태그를 사용하여 Android xml에서 직접 동적 문자열 스타일을 설정합니다.

17700 단어 htmlandroidxml
Android에서 문자열은 일반 텍스트를 표시하는 뷰를 처리할 때 가장 일반적인 객체 중 하나입니다.사용자 인터페이스를 실현할 때, 텍스트는 종종 약간의 양식이 필요하다.스타일링 문자열에 대해 우리는 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가 아니라 문자열이 필요합니다.이것은 동적 텍스트 자리 차지 문자가 정확하게 바뀌지만, 우리의 CharSequenceString 로 바뀌어 스타일을 포기해야 한다는 것을 의미한다.
HTML 태그를 처리하기 위해 안드로이드는 HtmlCompat을 제공합니다.이것은 문자열 자원으로 시작하는 안전하지 않은 문자를 인코딩해야 한다. 즉, '<', 즉 '&lt;'
<string name="lorem_ipsum">
   This is &lt;font color="red">red&lt;/font> 
   and this &lt;b>&lt;i>bold and italic (nested); &lt;/i>this just bold&lt;/b>,
   &lt;u>underlined&lt;/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

비록 그것은 효과적이며 에 의해 추천된 방법이지만 나는 개인적으로 이전의 어떤 방법도 좋아하지 않는다.왜?
  • 동적 텍스트 자리 표시자
  • 를 사용하기 위해 xml 문자열 자원을 완전히 변경했습니다.
  • 문자열 자원의 양식화 부분에서 xml 하이라이트 디스플레이를 잃어버려서 더 읽기 어려워요
  • official documentation
    더 좋은 방법은 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 hereMarkus Spiske

    좋은 웹페이지 즐겨찾기