Android中如何将字符串格式化与Annotation结合实现多字体TextView?
解决方案:动态格式化字符串+自定义字体分段设置
这个问题确实挺常见的——官方标注(annotation)仅支持静态字符串,而Html.fromHtml()又不支持自定义字体,不过咱们有几个靠谱的办法能实现你的需求,让到期日期用Montserrat SemiBold,其余文本用Regular:
方法1:用SpannableStringBuilder手动定位并设置字体
这种方法适合保留原单个字符串资源的场景,核心思路是先完成字符串格式化,再找到动态插入的日期位置,给该段文本单独设置字体:
Kotlin 代码示例(直接使用)
val expiryDate = "Apr 9, 2020" // 先完成字符串格式化 val fullText = context.resources.getString(R.string.description, expiryDate) // 定位到期日期在完整文本中的位置 val dateStartIndex = fullText.indexOf(expiryDate) val dateEndIndex = dateStartIndex + expiryDate.length // 创建Spannable对象并设置字体样式 val spannable = SpannableStringBuilder(fullText) val semiBoldTypeface = ResourcesCompat.getFont(context, R.font.montserrat_semibold) spannable.setSpan( TypefaceSpan(semiBoldTypeface), dateStartIndex, dateEndIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ) // 给TextView设置最终的富文本 yourTextView.text = spannable
适配DataBinding的版本(BindingAdapter)
如果想用DataBinding直接绑定,可以写一个自定义BindingAdapter,这样在XML里就能直接用:
@BindingAdapter("formattedTextWithCustomFont") fun TextView.setFormattedTextWithCustomFont(textRes: Int, dynamicParam: String) { val fullText = context.resources.getString(textRes, dynamicParam) val paramStartIndex = fullText.indexOf(dynamicParam) val paramEndIndex = paramStartIndex + dynamicParam.length val spannable = SpannableStringBuilder(fullText) val semiBoldTypeface = ResourcesCompat.getFont(context, R.font.montserrat_semibold) spannable.setSpan( TypefaceSpan(semiBoldTypeface), paramStartIndex, paramEndIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ) this.text = spannable }
然后在XML中调用:
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:formattedTextWithCustomFont="@{@string/description, expiry_date}" />
方法2:拆分字符串资源,分段拼接富文本
如果担心indexOf找不到动态文本(比如极端情况下文本重复),可以把原字符串拆成三个静态资源,分别拼接并设置字体,这种方法更稳妥:
第一步:拆分字符串资源
<string name="description_prefix">Your trial ends on </string> <string name="description_suffix">. You will be charged after your trial ends </string>
第二步:分段拼接并设置字体
val expiryDate = "Apr 9, 2020" val prefix = SpannableStringBuilder(context.resources.getString(R.string.description_prefix)) // 给到期日期设置半粗体 val dateSpan = SpannableString(expiryDate).apply { setSpan( TypefaceSpan(ResourcesCompat.getFont(context, R.font.montserrat_semibold)), 0, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ) } val suffix = SpannableStringBuilder(context.resources.getString(R.string.description_suffix)) // 拼接成完整富文本 val fullSpannable = prefix.append(dateSpan).append(suffix) yourTextView.text = fullSpannable
这两种方法都能完美避开官方annotation和Html.fromHtml的限制,实现你想要的自定义字体分段效果。
内容的提问来源于stack exchange,提问作者Karthikeyan Subramanian
相关产品推荐
相关产品推荐

