如何使用支持库字体功能作为 TextView 内容的一部分(使用 spannable)? [英] How to use support library fonts feature as a part of the TextView content (using spannable)?

查看:21
本文介绍了如何使用支持库字体功能作为 TextView 内容的一部分(使用 spannable)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

支持库(文档

我仍然很确定可以使用 fromHtml,但这可能不值得.

我也想知道,如果我们想要同时使用基本的 HTML 标签和我们为字体设置的自定义标签,如果我们确实在那里使用了 annotation,应该怎么做.

Background

The support library (docs here) allows you to use TTF fonts files in the "res/font" folder, either in XML :

app:fontFamily="@font/lato_black"

or via code:

val typeface = ResourcesCompat.getFont(context, R.font.lato_black)

The problem

While I know it's possible to use spannable technique to set different styles in parts of the TextView content (such as bold, italic, colors,etc...) , the only thing I've found for setting a different font, is by using the built in fonts of the OS, as shown here, but I can't see a way to do it for the new way to load fonts.

What I've tried

I tried to find a way to convert between the two, but with no luck. Of course, I also tried to find in the docs of possible functions, and I've tried to find about it over the Internet.

The question

How to set different font for different parts of the TextView ?

For example, in the text "Hello world", set the "Hello" to have the font of "lato_black" , and the default for the rest.


EDIT: Since I got about the same answer from 2 different people, I can't accept one over the other. Gave them both +1 for the effort, and I've changed the question a bit:

How would I set the font style to a part of the text, easily, while having the strings.xml file define it using a customized font-tag.

For example, this could be in the strings.xml file to set it as I've asked above :

<string name="something" ><customFont fontResource="lato_black">Hello</customFont> world</string>

Then, in code, all you would do is use something like:

textView.setText (Html.fromHtml(text, null, CustomFontTagHandler()))

I think it's very important, because translated strings might have become too different from what's in English, so you can't just parse the text of the string and then choose where to set the custom font. It has to be inside the strings file.

解决方案

Since both answers of MJM and TheMatrix are practically the same (yet over-complex for me) and both were answered around the same time, I couldn't just choose one of them, so I granted +1 for each, asking them to make it shorter yet support XML tag for easier handling with strings file.

For now, here's the much shorter version of how to set a custom font for a part of the text in the TextView:

class CustomTypefaceSpan(private val typeface: Typeface?) : MetricAffectingSpan() {
    override fun updateDrawState(paint: TextPaint) {
        paint.typeface=typeface
    }

    override fun updateMeasureState(paint: TextPaint) {
        paint.typeface=typeface
    }
}

Sample usage :

    val text = "Hello world"
    val index = text.indexOf(' ')
    val spannable = SpannableStringBuilder(text)
    spannable.setSpan(CustomTypefaceSpan(ResourcesCompat.getFont(this, R.font.lato_light)), 0, index, Spanned.SPAN_EXCLUSIVE_INCLUSIVE)
    spannable.setSpan(CustomTypefaceSpan(ResourcesCompat.getFont(this, R.font.lato_bold)), index, text.length, Spanned.SPAN_EXCLUSIVE_INCLUSIVE)
    textView.text = spannable


EDIT: seems Google provided a video about this, here :

class CustomTypefaceSpan(val font: Typeface?) : MetricAffectingSpan() {
    override fun updateMeasureState(textPaint: TextPaint) = update(textPaint)
    override fun updateDrawState(textPaint: TextPaint?) = update(textPaint)

    private fun update(tp: TextPaint?) {
        tp.apply {
            val old = this!!.typeface
            val oldStyle = old?.style ?: 0
            val font = Typeface.create(font, oldStyle)
            typeface = font
        }
    }
}

And the solution of handling it in strings.xml is also talked about on the video, here , yet using annotations instead of new HTML tags. Example:

strings.xml

<string name="title"><annotation font="lato_light">Hello</annotation> <annotation font="lato_bold">world</annotation></string>

MainActivity.kt

    val titleText = getText(R.string.title) as SpannedString
    val spannable = SpannableStringBuilder(titleText)
    val annotations = titleText.getSpans(0, titleText.length, android.text.Annotation::class.java)
    for (annotation in annotations) {
        if(annotation.key=="font"){
            val fontName=annotation.value
            val typeface= ResourcesCompat.getFont(this@MainActivity,resources.getIdentifier(fontName,"font",packageName))
            spannable.setSpan(CustomTypefaceSpan(typeface),spannable.getSpanStart(annotation),spannable.getSpanEnd(annotation), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
        }
    }
    textView.text = spannable

And the result:

Still I'm pretty sure it's possible to use fromHtml, but it's probably not worth it.

I also wonder what should be done if we want to use both the basic HTML tags and the cusomzied one we've set for font, if we indeed use annotation there.

这篇关于如何使用支持库字体功能作为 TextView 内容的一部分(使用 spannable)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆