Android中如何为字符串资源内指定文字设置特定语言字体
实现TextView混合孟加拉语与英文字体的方案
嘿,这个需求其实很好解决,Android里的SpannableString就是专门用来处理这种局部文本样式差异的场景,我来给你一步步讲怎么实现:
核心思路
给TextView设置默认的孟加拉语字体,然后用SpannableString把文本里的英文名称(Bill Gates、Paul Allen、Microsoft)单独替换成英文字体,其他部分保留原孟加拉语字体。
具体步骤
1. 准备字体文件
把你的孟加拉语字体(比如BanglaFont.ttf)和想要用的英文字体(比如Roboto-Regular.ttf,也可以用系统默认英文字体)放在项目的assets/fonts/目录下(如果没有fonts文件夹就新建一个)。
2. 加载字体
在Activity/Fragment里加载这两种字体:
// Java 代码 Typeface banglaTypeface = Typeface.createFromAsset(getAssets(), "fonts/BanglaFont.ttf"); // 用系统默认英文字体的话可以直接用 Typeface.DEFAULT Typeface englishTypeface = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Regular.ttf");
如果是Kotlin开发:
// Kotlin 代码 val banglaTypeface = Typeface.createFromAsset(assets, "fonts/BanglaFont.ttf") val englishTypeface = Typeface.createFromAsset(assets, "fonts/Roboto-Regular.ttf")
3. 自定义TypefaceSpan(关键!)
Android原生的TypefaceSpan只支持系统自带的字体家族,没法直接用我们自定义的字体,所以需要自己写一个CustomTypefaceSpan类来适配:
Java版
public class CustomTypefaceSpan extends TypefaceSpan { private final Typeface mTypeface; public CustomTypefaceSpan(Typeface typeface) { super(""); // 这里传空字符串,因为我们不用系统字体家族 mTypeface = typeface; } @Override public void updateDrawState(TextPaint ds) { applyCustomTypeface(ds, mTypeface); } @Override public void updateMeasureState(TextPaint paint) { applyCustomTypeface(paint, mTypeface); } private static void applyCustomTypeface(Paint paint, Typeface typeface) { int oldStyle; Typeface oldTypeface = paint.getTypeface(); oldStyle = oldTypeface == null ? 0 : oldTypeface.getStyle(); // 处理字体样式的兼容(比如粗体、斜体) int fakeStyle = oldStyle & ~typeface.getStyle(); if ((fakeStyle & Typeface.BOLD) != 0) { paint.setFakeBoldText(true); } if ((fakeStyle & Typeface.ITALIC) != 0) { paint.setTextSkewX(-0.25f); } paint.setTypeface(typeface); } }
Kotlin版
class CustomTypefaceSpan(private val typeface: Typeface) : TypefaceSpan("") { override fun updateDrawState(ds: TextPaint) { applyCustomTypeface(ds, typeface) } override fun updateMeasureState(paint: TextPaint) { applyCustomTypeface(paint, typeface) } private fun applyCustomTypeface(paint: Paint, typeface: Typeface) { val oldTypeface = paint.typeface val oldStyle = oldTypeface?.style ?: 0 val fakeStyle = oldStyle and typeface.style.inv() if (fakeStyle and Typeface.BOLD != 0) { paint.isFakeBoldText = true } if (fakeStyle and Typeface.ITALIC != 0) { paint.textSkewX = -0.25f } paint.typeface = typeface } }
4. 构建SpannableString并设置给TextView
接下来我们需要找到文本里的英文名称位置,给它们设置英文字体:
Java版
// 获取字符串资源里的完整文本 String fullText = getString(R.string.your_bangla_string); SpannableString spannableText = new SpannableString(fullText); // 定义需要替换成英文字体的目标文本 List<String> targetNames = Arrays.asList("Bill Gates", "Paul Allen", "Microsoft"); for (String target : targetNames) { int startIndex = fullText.indexOf(target); // 处理文本中可能出现多次的情况 while (startIndex != -1) { int endIndex = startIndex + target.length(); // 给目标文本设置英文字体 spannableText.setSpan(new CustomTypefaceSpan(englishTypeface), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 继续找下一个出现的位置 startIndex = fullText.indexOf(target, endIndex); } } // 设置TextView的默认字体为孟加拉语,再把SpannableString传进去 TextView textView = findViewById(R.id.your_text_view); textView.setTypeface(banglaTypeface); textView.setText(spannableText);
Kotlin版
val fullText = getString(R.string.your_bangla_string) val spannableText = SpannableString(fullText) val targetNames = listOf("Bill Gates", "Paul Allen", "Microsoft") targetNames.forEach { target -> var startIndex = fullText.indexOf(target) while (startIndex != -1) { val endIndex = startIndex + target.length spannableText.setSpan(CustomTypefaceSpan(englishTypeface), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) startIndex = fullText.indexOf(target, endIndex) } } val textView = findViewById<TextView>(R.id.your_text_view) textView.typeface = banglaTypeface textView.text = spannableText
注意事项
- 如果你的字符串里英文名称的大小写有变化,记得调整匹配的目标文本,或者用忽略大小写的匹配方式(比如
toLowerCase()后再找索引)。 - 如果用系统默认英文字体,直接把
englishTypeface换成Typeface.DEFAULT就行,不用额外加载字体文件。
内容的提问来源于stack exchange,提问作者Bashir Fardoush




