You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动