如何更改PopupMenu项目字体

时间:2014-11-16 14:19:29

标签: android popupmenu

我想更改 PopupMenu 项的默认字体,并使用我的自定义字体。

这是我用于创建 PopupMenu

的代码
PopupMenu pm = new PopupMenu(this, v);
getMenuInflater().inflate(R.menu.main, pm.getMenu());
pm.show();

菜单项目:

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

如果您与我分享您的建议,我将非常感激: - )

此致

4 个答案:

答案 0 :(得分:8)

检查我的解决方案是否存在同样的问题:

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);
        }

    }

在此方法中应用您的字体,您也可以更改字体颜色:

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

    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);
    }
}

答案 1 :(得分:2)

你可以使用反射。它可用于弹出菜单项的任何自定义。 android支持中菜单项的资源布局在android.support.v7.internal.view.menu.MenuPopupHelper中定义,其字段名称为“ITEM_LAYOUT”,声明为static final;它的价值等于“R.layout.abc_popup_menu_item_layout” 我在Grepcode中找到布局文件并将其复制到我的项目布局目录中。我把它命名为popup_menu_item_layout.xml。我的弹出菜单项布局来到这里

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

然后创建自定义类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);
    }
}
}

最后通过反射替换菜单项的布局资源ID;在您的主要活动onCreate方法或您的app onCreate方法中的某些地方:

    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);
}

答案 2 :(得分:1)

我知道这是一个古老的问题,但是如果像我这样的人偶然发现了这个特定问题以寻找明确的答案,我仍然想回答。

不知道AppCompat,但是在玩MaterialComponents并发现了API textAppearanceLargePopupMenu。例如,假设您要为应用程序中的所有PopupMenu应用特定的字体,然后定义一个style并将其应用于您的theme

示例样式:

<style name="AppTheme.TextAppearance.Popup" parent="TextAppearance.MaterialComponents.Caption">
    <item name="fontFamily">@font/opensans_regular</item>
</style>

示例主题:

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    <!-- All other attrs and styles -->
    <item name="textAppearanceLargePopupMenu">@style/AppTheme.TextAppearance.Popup</item>
</style>

答案 3 :(得分:-1)

我认为这是不可能的。 实际上你可以使用popupWindow并根据需要自定义它。