I want to change the default font of PopupMenu items and use from my custom font for them.
This is the code that I used for creating PopupMenu :
PopupMenu pm = new PopupMenu(this, v);
getMenuInflater().inflate(R.menu.main, pm.getMenu());
pm.show();
And the menu Items :
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/Setting"
android:title="Setting"/>
<item
android:id="@+id/About"
android:title="About"/>
<item
android:id="@+id/Help"
android:title="Help"/>
</menu>
I will be so thankful if you share your suggestions with me :-)
Regards
Check my solution for same issue :
Popup Menu Mehthod :
private void showEditPopupWindow(Context mContext) {
PopupMenu popupMenu = new PopupMenu(mContext, view);
popupMenu.getMenuInflater().inflate(R.menu.YOUR_MENU, popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.delete) {
// Do your stuffs;
} else {
// Do your stuffs
}
return true;
}
});
Menu menu = popupMenu.getMenu();
for (int i = 0; i < menu.size(); i++) {
MenuItem mi = menu.getItem(i);
applyFontToMenuItem(mi);
}
}
Apply your font in this method , also you can change color of font:
private void applyFontToMenuItem(MenuItem mi) {
Typeface font = Typeface.createFromAsset(mContext.getAssets(), "fonts/YOUR_FONT.ttf");
SpannableString mNewTitle = new SpannableString(mi.getTitle());
mNewTitle.setSpan(new CustomTypeFaceSpan("", font,Color.WHITE), 0, mNewTitle.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
mi.setTitle(mNewTitle);
}
CustomTypeFaceSpan Class :
public class CustomTypeFaceSpan extends TypefaceSpan {
private final Typeface newType;
private final int mColor;
public CustomTypeFaceSpan(String family, Typeface type, @ColorInt int color) {
super(family);
newType = type;
mColor = color;
}
@Override
public void updateDrawState(TextPaint ds) {
ds.setColor(mColor);
applyCustomTypeFace(ds, newType);
}
@Override
public void updateMeasureState(TextPaint paint) {
applyCustomTypeFace(paint, newType);
}
@Override
public int getSpanTypeId() {
return super.getSpanTypeId();
}
@ColorInt
public int getForegroundColor() {
return mColor;
}
private static void applyCustomTypeFace(Paint paint, Typeface tf) {
int oldStyle;
Typeface old = paint.getTypeface();
if (old == null) {
oldStyle = 0;
} else {
oldStyle = old.getStyle();
}
int fake = oldStyle & ~tf.getStyle();
if ((fake & Typeface.BOLD) != 0) {
paint.setFakeBoldText(true);
}
if ((fake & Typeface.ITALIC) != 0) {
paint.setTextSkewX(-0.25f);
}
paint.setTypeface(tf);
}
}
I know this is an old question but still want to answer, if, someone like me, stumbles upon this particular question looking for a definite answer.
Don't know about AppCompat
, but was playing with MaterialComponents
and found out the api textAppearanceLargePopupMenu
. An example, supose you want to apply a particular font for all PopupMenu
s in your app, then define a style
and apply this to your theme
:
Example Style:
<style name="AppTheme.TextAppearance.Popup" parent="TextAppearance.MaterialComponents.Caption">
<item name="fontFamily">@font/opensans_regular</item>
</style>
Example Theme:
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- All other attrs and styles -->
<item name="textAppearanceLargePopupMenu">@style/AppTheme.TextAppearance.Popup</item>
</style>
you can use reflection. It can be used for any customization of popup menu items.
The resource layout of menu item in android support is defined in android.support.v7.internal.view.menu.MenuPopupHelper and it 's field name is "ITEM_LAYOUT" that declared as static final; It 's value equals to "R.layout.abc_popup_menu_item_layout"
I find the layout file in Grepcode and copy it to my project layout directory. I named it popup_menu_item_layout.xml. My popup menu item layout comes here
<?xml version="1.0" encoding="utf-8"?>
<mypackage.PopupMenuItemView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?attr/dropdownListPreferredItemHeight"
android:minWidth="196dip"
android:paddingRight="16dip">
<!-- Icon will be inserted here. -->
<!-- The title and summary have some gap between them, and this 'group' should be centered vertically. -->
<RelativeLayout
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dip"
android:duplicateParentState="true">
<TextView
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:textAppearance="?attr/textAppearanceLargePopupMenu"
android:singleLine="true"
android:duplicateParentState="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"/>
<TextView
android:id="@+id/shortcut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_alignParentLeft="true"
android:textAppearance="?attr/textAppearanceSmallPopupMenu"
android:singleLine="true"
android:duplicateParentState="true"/>
</RelativeLayout>
<!-- Checkbox, and/or radio button will be inserted here. -->
Then create custom class PopupMenuItemView:
public class PopupMenuItemView extends android.support.v7.internal.view.menu.ListMenuItemView {
public PopupMenuItemView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PopupMenuItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
applyTypefaceToAll(this, your_typeface);
TypefaceUtils.applyTextSizeToAll(this, your_textsize);
}
public static void applyTypefaceToAll(View view, Typeface typeface) {
if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int childIndex = 0; childIndex < viewGroup.getChildCount(); childIndex++)
applyTypefaceToAll(viewGroup.getChildAt(childIndex), typeface);
} else if (view instanceof TextView) {
TextView textView = (TextView) view;
textView.setTypeface(typeface);
textView.setPaintFlags(textView.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG | Paint.DEV_KERN_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
}
}
public static void applyTextSizeToAll(View view, float size) {
if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int childIndex = 0; childIndex < viewGroup.getChildCount(); childIndex++)
applyTextSizeToAll(viewGroup.getChildAt(childIndex), size);
} else if (view instanceof TextView) {
TextView textView = (TextView) view;
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
textView.setPaintFlags(textView.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG | Paint.DEV_KERN_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
}
}
}
Finally replace layout resource id for menu items by reflection; some where like in your main activity onCreate method or in your app onCreate method:
try {
setFinalStatic(MenuPopupHelper.class.getDeclaredField("ITEM_LAYOUT"),
R.layout.popup_menu_item_layout);
} catch (Exception e) {
e.printStackTrace();
}
public static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
try {
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}catch (Exception e) {
e.printStackTrace();
}
field.set(null, newValue);
}
I think it's not possible.
Actually you can use popupWindow and customize it like menu as you want.