如何在ActionBar的"溢出"菜单中显示图标

Mih*_*hir 64 android android-menu actionbarsherlock android-actionbar

我知道使用本机API是不可能的.是否有解决方法来实现这种视图?

Sim*_*mon 84

一般来说,之前发布的答案是可以的.但它基本上删除了溢出菜单的默认行为.可以在不同的屏幕尺寸上显示多少个图标,然后当它们无法显示时,它们会进入溢出菜单.通过执行上述操作,您可以删除许多重要功能.

更好的方法是告诉溢出菜单直接显示图标.您可以通过将以下代码添加到Activity来完成此操作.

@Override
public boolean onMenuOpened(int featureId, Menu menu)
{
    if(featureId == Window.FEATURE_ACTION_BAR && menu != null){
        if(menu.getClass().getSimpleName().equals("MenuBuilder")){
            try{
                Method m = menu.getClass().getDeclaredMethod(
                    "setOptionalIconsVisible", Boolean.TYPE);
                m.setAccessible(true);
                m.invoke(menu, true);
            }
            catch(NoSuchMethodException e){
                Log.e(TAG, "onMenuOpened", e);
            }
            catch(Exception e){
                throw new RuntimeException(e);
            }
        }
    }
    return super.onMenuOpened(featureId, menu);
}
Run Code Online (Sandbox Code Playgroud)

  • **警告**:在`appcompat-v7:22.x`中不再调用`onMenuOpened(FEATURE_ACTION_BAR)`,这可能是也可能不是故意的,请参阅http://b.android.com/171440.应该可以将代码移动到`onPrepareOptionsMenu`. (13认同)
  • 这应该是公认的答案,另一个更快捷. (5认同)
  • 这是因为您正在使用AppCompat/SupportLibrary.您需要将菜单的完整类名添加到ProGuard脚本中.在这种情况下,它的"android.support.v7.internal.view.menu.MenuBuilder" (4认同)
  • 这种方法停止了对最新版本的支持库的影响...重写onPrepareOptionsPanel()方法而不是..请看其他答案:http://stackoverflow.com/a/30337653/684582 (4认同)
  • `featureId == Window.FEATURE_ACTION_BAR`不起作用,我用`(featureId&Window.FEATURE_ACTION_BAR)== Window.FEATURE_ACTION_BAR`修复它,它有效! (3认同)
  • 2.3.7没有ActionBar,默认情况下它在选项菜单中有图标. (2认同)

iBa*_*bur 54

在菜单xml中,使用以下语法嵌套菜单,您将开始获取带有图标的菜单

<item
    android:id="@+id/empty"
    android:icon="@drawable/ic_action_overflow"
    android:orderInCategory="101"
    android:showAsAction="always">
    <menu>
        <item
            android:id="@+id/action_show_ir_list"
            android:icon="@drawable/ic_menu_friendslist"
            android:showAsAction="always|withText"
            android:title="List"/>
    </menu>
</item>
Run Code Online (Sandbox Code Playgroud)

  • 我没想到会那么容易! (2认同)

lba*_*osa 39

基于之前的答案尝试了这一点并且它工作正常,至少在支持库的更新版本(25.1)中:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);

    if(menu instanceof MenuBuilder){
        MenuBuilder m = (MenuBuilder) menu;
        //noinspection RestrictedApi
        m.setOptionalIconsVisible(true);
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

  • 使用Android支持25.3.1"MenuBuilder.setOptionalIconsVisible"只能在同一个库组中调用(groupId = com.android.support) (6认同)
  • @FrancescoVadicamo `@SuppressLint("RestrictedApi")` (3认同)
  • 谢谢,反射使我感到震惊。:)最好将它变成公认的答案。 (2认同)

Des*_*Lua 22

您可以使用SpannableString

public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_tab, menu);

    MenuItem item = menu.findItem(R.id.action_login);
    SpannableStringBuilder builder = new SpannableStringBuilder("* Login");
    // replace "*" with icon
    builder.setSpan(new ImageSpan(this, R.drawable.login_icon), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    item.setTitle(builder);
}
Run Code Online (Sandbox Code Playgroud)


use*_*975 13

Simon给出的答案对我非常有用,所以我想分享一下我如何onCreateOptionsMenu按照建议将其实现到-method:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu items for use in the action bar
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_action_bar, menu);

    // To show icons in the actionbar's overflow menu:
    // http://stackoverflow.com/questions/18374183/how-to-show-icons-in-overflow-menu-in-actionbar
    //if(featureId == Window.FEATURE_ACTION_BAR && menu != null){
        if(menu.getClass().getSimpleName().equals("MenuBuilder")){
            try{
                Method m = menu.getClass().getDeclaredMethod(
                        "setOptionalIconsVisible", Boolean.TYPE);
                m.setAccessible(true);
                m.invoke(menu, true);
            }
            catch(NoSuchMethodException e){
                Log.e(TAG, "onMenuOpened", e);
            }
            catch(Exception e){
                throw new RuntimeException(e);
            }
        }
    //}

    return super.onCreateOptionsMenu(menu);
}
Run Code Online (Sandbox Code Playgroud)

  • 由于"setOptionalIconsVisible"方法是包本地的,我最终在我的项目中创建了一个具有相同名称的包,并创建了一个不必使用反射的辅助类.`package android.support.v7.view.menu; import android.view.Menu; 公共类菜单{公共静态无效setOptionalIconsVisible(菜单菜单){如果(菜单的instanceof使用MenuBuilder){使用MenuBuilder使用MenuBuilder =(使用MenuBuilder)菜单; menuBuilder.setOptionalIconsVisible(真); } (2认同)

Kev*_*ant 7

基于@Desmond Lua从上面得到的答案,我创建了一个静态方法,用于在下拉列表中使用XML中声明的drawable,并确保它的着色颜色不会影响Constant Drawable状态.

    /**
 * Updates a menu item in the dropdown to show it's icon that was declared in XML.
 *
 * @param item
 *         the item to update
 * @param color
 *         the color to tint with
 */
private static void updateMenuWithIcon(@NonNull final MenuItem item, final int color) {
    SpannableStringBuilder builder = new SpannableStringBuilder()
            .append("*") // the * will be replaced with the icon via ImageSpan
            .append("    ") // This extra space acts as padding. Adjust as you wish
            .append(item.getTitle());

    // Retrieve the icon that was declared in XML and assigned during inflation
    if (item.getIcon() != null && item.getIcon().getConstantState() != null) {
        Drawable drawable = item.getIcon().getConstantState().newDrawable();

        // Mutate this drawable so the tint only applies here
        drawable.mutate().setTint(color);

        // Needs bounds, or else it won't show up (doesn't know how big to be)
        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        ImageSpan imageSpan = new ImageSpan(drawable);
        builder.setSpan(imageSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        item.setTitle(builder);
    }
}
Run Code Online (Sandbox Code Playgroud)

在活动中使用时,使用它会看起来像这样.根据您的个人需求,这可能会更加优雅.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_activity_provider_connect, menu);
    int color = ContextCompat.getColor(this, R.color.accent_dark_grey);
    updateMenuWithIcon(menu.findItem(R.id.email), color);
    updateMenuWithIcon(menu.findItem(R.id.sms), color);
    updateMenuWithIcon(menu.findItem(R.id.call), color);
    return true;
}
Run Code Online (Sandbox Code Playgroud)


Men*_*amm 5

当前最好但未被接受的解决方案可能适用于较旧的平台。无论如何,在新的 AppCompat21+ 中,所需的方法不存在并且方法getDeclaredMethod返回异常NoSuchMethodException

所以我的解决方法(在 4.x、5.x 设备上测试和工作)基于直接更改背景参数。因此,只需将此代码放入您的 Activity 类中即可。

@Override
public boolean onMenuOpened(int featureId, Menu menu) {
    // enable visible icons in action bar
    if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {
        if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
            try {
                Field field = menu.getClass().
                        getDeclaredField("mOptionalIconsVisible");
                field.setAccessible(true);
                field.setBoolean(menu, true);
            } catch (IllegalAccessException | NoSuchFieldException e) {
                Logger.w(TAG, "onMenuOpened(" + featureId + ", " + menu + ")", e);
            }
        }
    }
    return super.onMenuOpened(featureId, menu);
}
Run Code Online (Sandbox Code Playgroud)

  • 你有没有可能忘记告诉 ProGuard?`-keepclassmembers **.MenuBuilder { void setOptionalIconsVisible(boolean); }` (3认同)

小智 5

我发现的最简单的方法是这样的:

public boolean onCreateOptionsMenu(Menu menu){
     MenuInflater inflater = getMenuInflater();
     inflater.inflate(R.menu.toolbar_menu,menu);
     if(menu instanceof MenuBuilder) {  //To display icon on overflow menu

          MenuBuilder m = (MenuBuilder) menu; 
          m.setOptionalIconsVisible(true);

     }
   return true;
}        `
Run Code Online (Sandbox Code Playgroud)