You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Android选项菜单项设置自定义字体?

解决Options Menu自定义字体不生效的问题

我懂你遇到的困扰——自定义TTF字体在App的大部分视图都正常工作,唯独Options Menu里不生效,对吧?咱们先分析下现有代码的潜在问题,再给出可行的解决办法。

问题分析

你的代码里已经尝试通过SpannableString结合CustomTypefaceSpan给菜单项设置字体,但可能踩了两个坑:

  • 菜单生命周期顺序问题:onCreateOptionsMenu只会在菜单首次创建时调用一次,系统后续可能会缓存菜单项的样式,导致你的SpannableString被覆盖。
  • 系统Menu控件的样式优先级:部分安卓版本的系统Menu会忽略SpannableString的字体设置,优先使用系统默认样式。

解决方案

方案1:改用onPrepareOptionsMenu设置字体

onPrepareOptionsMenu会在每次菜单打开前被调用,能确保样式及时刷新,避免系统缓存问题。修改你的代码如下:

@Override 
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    menu.clear();
    inflater.inflate(R.menu.menu_apply, menu);
}

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    MenuItem applyItem = menu.findItem(R.id.action_apply);
    if (applyItem != null) {
        Typeface typeface = Utils.getTypefaceForAppLanguage(getContext());
        String title = Utils.getLanguageValue(getString(R.string.action_apply));
        // 设置带自定义字体的标题
        applyItem.setTitle(typeface != null ? CommonUtils.getStringWithTypeface(typeface, title) : title);
    }
    return super.onPrepareOptionsMenu(menu);
}

方案2:使用自定义MenuItem布局(最稳妥)

如果方案1还是不生效,说明系统Menu控件强制覆盖了样式,这时候可以用自定义View完全控制菜单项的显示:

  1. 创建自定义菜单项布局res/layout/menu_item_custom.xml:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tv_menu_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingHorizontal="16dp"
    android:paddingVertical="8dp"
    android:textColor="@color/menu_text_color"
    android:textSize="16sp" />
  1. 在onPrepareOptionsMenu中设置自定义View:
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    MenuItem applyItem = menu.findItem(R.id.action_apply);
    if (applyItem != null) {
        Typeface typeface = Utils.getTypefaceForAppLanguage(getContext());
        String title = Utils.getLanguageValue(getString(R.string.action_apply));
        
        // 加载自定义布局
        View customMenuItem = LayoutInflater.from(getContext()).inflate(R.layout.menu_item_custom, null);
        TextView titleTv = customMenuItem.findViewById(R.id.tv_menu_title);
        titleTv.setText(title);
        if (typeface != null) {
            titleTv.setTypeface(typeface);
        }
        
        // 给菜单项设置自定义View
        applyItem.setActionView(customMenuItem);
    }
    return super.onPrepareOptionsMenu(menu);
}

补充说明

你的CustomTypefaceSpan实现是正确的,它通过重写updateDrawState和updateMeasureState方法,确保字体样式能应用到TextPaint上,所以不用修改这部分代码。

我之前做多语言适配时也遇到过一模一样的问题,用方案1解决了大部分机型的问题,少数顽固机型就用方案2,亲测有效!

内容的提问来源于stack exchange,提问作者andro-girl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:27:24