如何更改Android菜单项的自定义字体?

33
我有以下的Android Java和XML代码。我想要改变我的应用程序菜单项的字体。我只知道我们可以使用setTypeface更改TextView的字体,但找不到任何更改菜单项字体的方法。
JAVA Code-:
@Override
public boolean onCreateOptionsMenu(Menu menu) {    
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main, menu);
    return true;
}

@Override    
public boolean onOptionsItemSelected(MenuItem item) {
   switch (item.getItemId()) {     
        case R.id.action_refresh1:                                          
            Toast.makeText(this, "Item1 Selected", Toast.LENGTH_SHORT)
            .show();      
        break;

        case R.id.action_refresh2:                                          
            Toast.makeText(this, "Item2 Selected", Toast.LENGTH_SHORT)
            .show();      
            break;

        default:      
            break;
   }
}

XML 代码:

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
    android:id="@+id/action_refresh1"
    android:orderInCategory="100"
    android:showAsAction="always"
    android:title="Item1"/>

<item
    android:id="@+id/action_refresh2"
    android:orderInCategory="100"
    android:showAsAction="always"
    android:title="Item2"/>
</menu>

我想要改变两个菜单项的字体,但不知道如何将settypface集成到菜单项中。


1
也许这会给你一些提示 :) 请参见下面的答案 :) https://dev59.com/9W855IYBdhLWcg3wz3vo - superJen
10个回答

24

在styles.xml中创建样式

 <style name="Style_TextView">
            <item name="fontFamily">@font/myriadproregular</item>
 </style>
将以下代码添加到android.support.design.widget.NavigationView中
 app:itemTextAppearance="@style/Style_TextView"

注意:此方法适用于 android.support.design.widget.NavigationView


1
谢谢,我找了好几个小时才找到一个关于28之前的答案。 - Janwilx72
1
最简单和快速的解决方案。谢谢。 - Parth Patel

23

您需要为菜单项提供自定义布局。

首先,在您的菜单XML中设置以下内容之一:

情况1,如果您正在使用支持库:

<menu
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_save"
        android:title="@string/action_save"
        android:icon="@drawable/ic_action_save"
        android:orderInCategory="100"
        app:showAsAction="always"
        app:actionLayout="@layout/layout_menu_save"/>
</menu>

情况2 如果您使用支持库:

<menu
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/action_save"
        android:title="@string/action_save"
        android:icon="@drawable/ic_action_save"
        android:orderInCategory="100"
        android:showAsAction="always"
        android:actionLayout="@layout/layout_menu_save"/>
</menu>

然后在actionLayout中(例如我的示例中的layout_menu_save.xml)编写以下内容:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:background="@drawable/background_transparent_stateful">

    <com.example.YourCustomTypefaceTextView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:gravity="center_vertical"
        android:text="@string/action_save"/>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:gravity="center_vertical"
        android:src="@drawable/ic_action_save"
        android:contentDescription="@string/action_save"/>

</LinearLayout>

背景可绘制对象(background_transparent_stateful)在自定义布局上提供触摸反馈。

<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_pressed="true"
        android:drawable="#20FFFFFF">
    </item>
    <item
        android:drawable="@android:color/transparent">
    </item>
</selector>

这样,您将会得到一个左边带有自定义字体的文本标签,并在右边带有图标。

当然,您可以按照自己的喜好自定义布局!


编辑:
如果您使用支持库并且您的Activity主题扩展了AppCompatTheme,您可以获得典型的Lollipop“波纹效果”,以获得更好的触摸反馈效果。 只需用以下代码替换自定义背景即可:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:background="?attr/selectableItemBackgroundBorderless">
    ...
</LinearLayout>

3
这种方法有点用,但在L系统上不是很行。你需要将item.setOnMenuItemClickListener()改为item.getActionView().setOnClickListener(),并使你的LinearLayout可点击和可获取焦点以注册点击事件。此外,在动画后涟漪效果会停滞不前。 - Eduard
嗨@EduardK,感谢您的反馈!这可能是一个错误,我在某些特定的Activity配置中遇到了类似的行为。您是否正在使用Android支持库? - araks
4
好的,使用支持库。看起来我刚刚解决了它。只需要将clickable="true"和focusable="true"添加到LinearLayout中即可。然后,水波纹效果和点击都能正常工作。(不要添加focusableInTouchMode)。 - Eduard
谢谢你的修复。我会立即更新答案! - araks

19

将您选择的字体添加到基础应用程序主题中即可。请注意,这会使所选字体成为任何未指定字体属性的基本字体。

    <item name="android:fontFamily">@font/your_font</item>

2
请记住,如果您有values-21文件夹,则也可以在那里进行此更改。 - aligur

8

XML

<?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">

        <item
            android:id="@+id/action_edit"
            android:title="@string/edit"
            android:visible="true"
            app:showAsAction="always" />
    </menu>

在 Activity 或 Fragment 中

@Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

            Typeface face = Typeface.createFromAsset(getActivity().getAssets(),"fonts/OpenSans-Regular.ttf");    //  THIS
            TypefaceSpan face = new TypefaceSpan("<REPLACE_WITH_FONT_NAME>"); // OR  THIS 
            SpannableStringBuilder title = new SpannableStringBuilder(getContext().getString(R.string.edit));
            title.setSpan(face, 0, title.length(), 0);
            menu.add(Menu.NONE, R.id.action_edit, 0, title); // THIS 
            MenuItem menuItem = menu.findItem(R.id.action_edit); // OR THIS 
            menuItem.setTitle(title);
        super.onCreateOptionsMenu(menu, inflater);
    }

在我看来,为菜单项设置自定义字体的最佳方式。 - Eli
如果我想将下载的ttf文件设置为TypefaceSpan,该怎么办? - andro-girl

4

当您使用TypefaceSpan添加菜单项时,您还可以使用SpannableStringBuilder。对于每个菜单项,请执行以下操作:

TypefaceSpan span = new TypefaceSpan("<REPLACE_WITH_FONT_NAME>");
SpannableStringBuilder title = new SpannableStringBuilder("My Menu Item Title");
title.setSpan(span, 0, title.length(), 0);
menu.add(Menu.NONE, id, index, title);

4
如果你的应用只需要在Android Pie (API level 28)及以上版本中运行,你可以在onPrepareOptionsMenu中从Typeface构建一个TypefaceSpan。否则,你可以像answer所建议的那样使用CustomTypefaceSpan类。
public boolean onPrepareOptionsMenu(Menu menu) {
    int customFontId = R.font.metropolis_medium;
    for (int i = 0; i < menu.size(); i++) {
        MenuItem menuItem = menu.getItem(i);
        String menuTitle = menuItem.getTitle().toString();
        Typeface typeface = ResourcesCompat.getFont(this, customFontId);
        SpannableString spannableString = new SpannableString(menuTitle);
        // For demonstration purposes only, if you need to support < API 28 just use the CustomTypefaceSpan class only.
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
            TypefaceSpan typefaceSpan = typeface != null ?
                    new TypefaceSpan(typeface) :
                    new TypefaceSpan("sans-serif");
            spannableString.setSpan(typefaceSpan, 0, menuTitle.length(), 
                    Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
        } else {
            CustomTypefaceSpan customTypefaceSpan = typeface != null ?
                    new CustomTypefaceSpan(typeface) :
                    new CustomTypefaceSpan(Typeface.defaultFromStyle(Typeface.NORMAL));
            spannableString.setSpan(customTypefaceSpan, 0, menuTitle.length(),
                    Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
        }
        menuItem.setTitle(spannableString);
    }
    return true;
}

main.menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/settings"
        android:onClick="openSettings"
        android:title="@string/settings"
        app:showAsAction="never" />
    <item
        android:id="@+id/about"
        android:onClick="openAbout"
        android:title="@string/about"
        app:showAsAction="never" />
</menu>

之前和之后:

Before & After


1
由于这个问题更相关,我删除了在类似的问题中的回答。 - Sash Sinha

2
我发现这个解决方案对我很有用。希望它能帮助新的浏览者。
你的菜单 main.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
  <item android:id="@+id/item1"
  android:title="User"
  android:orderInCategory="100"
  android:visible="true"
  app:showAsAction="always"
  app:actionViewClass="android.widget.Button"
/>
</menu>

在您展开自定义菜单之后,您可以引用菜单项。当您获取菜单项的引用时,您将能够自定义该项以显示图标和Unicode文本。您的图标图像文件必须存储在

res/drawable文件夹中。

@Override
   public boolean onCreateOptionsMenu(Menu menu) {
     // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);

   //reference to the item of the menu
   MenuItem i=menu.findItem(R.id.item1);
   Button button_menu =(Button) i.getActionView();

   if(itemuser!=null){
   // Create Typeface object to use unicode font in assets folder
   Typeface font= Typeface.createFromAsset(getApplicationContext().getAssets(),"fonts/arial.ttf");
   // Set unicode font to menu item
   button_menu .setTypeface(font);  
   // Set item text and color
   button_menu .setText(getResources().getString(R.string._text));
   button_menu .setTextColor(Color.WHITE);
   // Make item background transparent
   button_menu .setBackgroundColor(Color.TRANSPARENT);
   // Show icon next to the text
   Drawable icon=getApplicationContext().getResources().getDrawable( R.drawable.user);
   button_menu .setCompoundDrawablesWithIntrinsicBounds( icon, null, null, null );
}

return true;

   }

2

只需将NavigationViewitemTextAppearance属性设置为系统或自定义样式:

 <android.support.design.widget.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:headerLayout="@layout/nav_header_main_navigation"
    app:itemBackground="@color/white"
    app:itemTextAppearance="@style/TextAppearance.AppCompat"
    app:itemTextColor="@color/saintpatrickblue"
    app:menu="@menu/activity_main_navigation_drawer"/>

这个可以工作。textAppearance 应该是样式而不是字体。我之前犯了使用字体而非样式的错误。加一分先生! - Simo Nyathi

1

@brahmyadigopula的回答很好。

这里只是为了简化而提供了更完整的版本:

菜单

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <item
        android:id="@+id/update"
        android:showAsAction="always"
        android:title="@string/menu_update"
        tools:ignore="UnusedAttribute"
        android:actionViewClass="android.widget.Button"/>
</menu>

在您的 Activity 或 Fragment 中:
        // Inflater the menu based on the layout above
        inflater.inflate(menuRes, menu);


        // Set font type face
        if (setCustomFontType){
            final MenuItem menuItem = menu.findItem(R.id.update);
            String title = menuItem.getTitle().toString();

            Button button_menu = (Button) menuItem.getActionView();
            button_menu.setTypeface("<REPLACE_WITH_FONT_NAME>");
            button_menu.setText(title);
            button_menu.setTextColor(Color.WHITE);
            button_menu.setBackgroundColor(_getResources().getColor(R.color.transparent_color));
            button_menu.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    onOptionsItemSelected(menuItem);
                }
            });
        }

        super.onCreateOptionsMenu(menu, inflater);

1
如果您正在使用android.support.design库,则:
在主题中:
app:itemTextAppearance="@style/bottom_navigation_textappreance"

如果您正在使用Material设计,则:
在XML中:
app:itemTextAppearanceActive="@style/bottom_navigation_textappreance" 
app:itemTextAppearanceInactive="@style/bottom_navigation_textappreance"

在主题中:
<style name="bottom_navigation_textappreance" parent="Widget.Design.BottomNavigationView">
    <item name="fontFamily">@font/fira_sans_bold</item>
</style>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接