如何为Android选项菜单项设置自定义字体?
我懂你遇到的困扰——自定义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完全控制菜单项的显示:
- 创建自定义菜单项布局
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" />
- 在
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
相关产品推荐
相关产品推荐

