33

I have the following Android Java and XML code. I want to change the font of Menu Items of my app. I know only that we can change the font of TextView using setTypeface but not able to find anyway for Menu Item.

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 Code-:

<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>

I want to change the font of two menu item , but don't know how to integrate settypface for Menu Item.

Chris Stillwell
  • 10,266
  • 10
  • 67
  • 77
Anshuman Pattnaik
  • 883
  • 3
  • 16
  • 37
  • 1
    maybe this will give you a hint :) see the answer below :) http://stackoverflow.com/questions/4135699/how-to-set-a-font-for-the-options-menu – superJen Feb 21 '14 at 18:50

10 Answers10

24

Create Style in styles.xml

 <style name="Style_TextView">
            <item name="fontFamily">@font/myriadproregular</item>
 </style>

Add Below code into android.support.design.widget.NavigationView

 app:itemTextAppearance="@style/Style_TextView"

Note: It works for android.support.design.widget.NavigationView

Suman
  • 1,307
  • 15
  • 32
23

you have to provide a custom layout for the menu item.

First, in your menu XML set one of the following

CASE 1 if you are using the support library:

<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>

CASE 2 if you are not using the support library:

<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>

Then in the actionLayout (layout_menu_save.xml in my example) write the following:

<?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>

The background drawable (background_transparent_stateful) is useful for having touch feedback on your custom layout:

<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>

This way you will have a text with custom font on the left as a label with an icon on the right.

Obviously you can customize the layout as you prefer!


EDIT:
If you are using the support library and your activity Theme extends the AppCompatTheme you can get the typical Lollipop "ripple effect" for a better looking touch feedback. Just replace the custom background with:

<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>
araks
  • 40,738
  • 8
  • 34
  • 39
  • 3
    Hm. This sort of works, but not really (at least on L). You need to change your item.setOnMenuItemClickListener() to item.getActionView().setOnClickListener(), and make your LinearLayout clickable and focusable in order to register clicks. Also, the ripple effect gets stuck after animating. – Eduard Jun 20 '15 at 18:54
  • Hi @EduardK. thanks for the feedback! It might be a bug, I encountered a similar behavior on some specific Activity configurations. Are you using the Android Support Library? – araks Jun 20 '15 at 18:58
  • 4
    Yep, using support library. Looks like I just fixed it. Need to only add clickable="true" and focusable="true" to LinearLayout. Then both, the ripple effect and clicks work properly. (do not add focusableInTouchMode) – Eduard Jun 20 '15 at 19:08
  • Thank you for the fix. I'll update the answer immediately! – araks Jun 20 '15 at 19:24
19

Just add the font of your choice to your base application theme. Note that that makes the selected font the base font for any unspecified font attributes.

    <item name="android:fontFamily">@font/your_font</item>
Simo Nyathi
  • 201
  • 2
  • 6
  • 2
    bear in mind that if you have values-21 folder then you can do this change on there as well – aligur Jul 03 '19 at 08:06
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>

IN ACTIVITY OR IN 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);
    }
NickUnuchek
  • 11,794
  • 12
  • 98
  • 138
4

You can also use a SpannableStringBuilder when you add a menu item with a TypefaceSpan. For each menu item do something like

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);
Stephen Johnson
  • 5,293
  • 1
  • 23
  • 37
4

If your app only needs to work on Android Pie (API level 28) and above you can construct a TypefaceSpan from a Typeface in onPrepareOptionsMenu. Otherwise you can use a CustomTypefaceSpan class like this answer suggests:

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:

Before & After

Sash Sinha
  • 18,743
  • 3
  • 23
  • 40
  • 1
    Deleted my answer in a [similar question](https://stackoverflow.com/questions/50680187/how-do-i-add-custom-font-on-menu-item-in-android/53993077#53993077) since this question seems more relevant. – Sash Sinha Jan 03 '19 at 17:02
2

I found this solution is usefull for me .hope it will help full new surfers.

your menu 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>

After you inflated the custom menu, you can make a reference to the item of the menu. When you obtain the reference to the menu item, you will be able to customize the item to show icon and Unicode text. Your icon image file has to be stored in the

res/drawable folder.

@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;

   }
brahmy adigopula
  • 617
  • 3
  • 15
2

Simply set itemTextAppearance property of the NavigationView to system or custom style:

 <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"/>
christian mini
  • 1,662
  • 20
  • 39
  • This works. the textAppearance should be a style and not the font. I had made the error of using font instead of style. +1 sir – Simo Nyathi Jul 18 '19 at 13:30
1

The answer by @brahmyadigopula works well.

Here is just a more complete version for the sake of simplification:

The Menu

<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>

In your Activity or 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);
Thiago
  • 12,778
  • 14
  • 93
  • 110
1

If you are using android.support.design library then:

In theme:

app:itemTextAppearance="@style/bottom_navigation_textappreance"

if you are using Material design then:

In XML:

app:itemTextAppearanceActive="@style/bottom_navigation_textappreance" 
app:itemTextAppearanceInactive="@style/bottom_navigation_textappreance"

In theme:

<style name="bottom_navigation_textappreance" parent="Widget.Design.BottomNavigationView">
    <item name="fontFamily">@font/fira_sans_bold</item>
</style>
Shahzeb
  • 3,696
  • 4
  • 28
  • 47
Android Geek
  • 596
  • 8
  • 14