【问题标题】:How To show icons in Overflow menu in ActionBar如何在 ActionBar 的溢出菜单中显示图标
【发布时间】:2013-08-24 19:32:21
【问题描述】:

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

【问题讨论】:

  • 我想为我的应用实现没关系。
  • 很好,但是如果你有另一个应用程序在做,那么你可以试一试,也许可以弄清楚它们的实现是如何工作的。 ActionBarSherlock 库可能是一个不错的起点,因为它为较旧的(4.0 之前的)设备创建了类似的视图。调整该实现应该不会太难。
  • 它在内部也使用了本地类,所以它不会起作用。

标签: android actionbarsherlock android-actionbar android-menu


【解决方案1】:

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

更好的方法是告诉溢出菜单直接显示图标。您可以通过将以下代码添加到您的活动来做到这一点。

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

【讨论】:

  • 这应该是公认的答案,另一个是一个快速的技巧。
  • 这是因为您使用的是 AppCompat/SupportLibrary。您需要将菜单的完整类名添加到 ProGuard 脚本中。在这种情况下,它的“android.support.v7.internal.view.menu.MenuBuilder”
  • 警告onMenuOpened(FEATURE_ACTION_BAR)appcompat-v7:22.x 中不再被调用,这可能是有意的,也可能不是有意的,请参阅b.android.com/171440。把代码移到onPrepareOptionsMenu应该没问题。
  • 这种方法停止在最新版本的支持库上工作......改为覆盖 onPrepareOptionsPanel() 方法......查看其他答案:stackoverflow.com/a/30337653/684582
  • featureId == Window.FEATURE_ACTION_BAR 不工作,我用(featureId & Window.FEATURE_ACTION_BAR) == Window.FEATURE_ACTION_BAR 修复它,它工作!
【解决方案2】:

在你的菜单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>

【讨论】:

  • 没想到这么简单!
  • 在尝试了很多之后,我也有同样的想法,我为其他一些任务进行了更改,但它也开始显示图标。
  • @drawable/ic_action_overflow 图像在android中是默认的,或者必须将它放在drawable中
  • 它是私有的,所以它不能直接访问,你需要把它放在你的资源中。你可以从下面的链接developer.android.com/design/downloads/index.html
  • @techtinkerer 你用什么方法做到的?
【解决方案3】:

根据之前的答案进行了尝试,并且效果很好,至少对于支持库的更新版本 (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;
}

【讨论】:

  • 谢谢,反思让我感到厌烦。 :) 让这成为公认的答案会很好。
  • 作品简洁美观。谢谢。
  • 使用 Android 支持 25.3.1 MenuBuilder.setOptionalIconsVisible 只能在同一个库组内调用 (groupId=com.android.support)
  • @FrancescoVadicamo @SuppressLint("RestrictedApi")
  • 这在这里不起作用,可能是因为我在 ToolBar 上定义了另一个图标(即溢出图标消失时)。此外,对 m.setOptionalIconsVisible 的调用仅限于调用它的包,另请参见 tim4dev 注释。
【解决方案4】:

你可以使用 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);
}

【讨论】:

  • 这个方案很棒,不需要依赖内部字段!
  • 缺少返回语句
【解决方案5】:

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

【讨论】:

  • 由于“setOptionalIconsVisible”方法是包本地的,我最终在我的项目中创建了一个同名的包,并创建了一个不必使用反射的辅助类。 package android.support.v7.view.menu; import android.view.Menu; public class Menus { public static void setOptionalIconsVisible(Menu menu) { if (menu instanceof MenuBuilder) { MenuBuilder menuBuilder = (MenuBuilder) menu; menuBuilder.setOptionalIconsVisible(true); } } }
  • @Makotosan 这个方法不再是包私有的! ;)
  • @LouisCAD 现在该方法仅限于库组,因此他们正在努力使其听起来无法访问。
【解决方案6】:

基于@Desmond Lua 对above 的回答,我创建了一个静态方法,用于在下拉列表中使用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);
    }
}

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

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

【讨论】:

  • 我只是想知道,Android 专家,如何修复/调整图标文本的垂直对齐方式?!简单吗?干杯!
  • 我不确定,但我的直觉只是在图标本身(例如在 Photoshop 中)上添加视觉填充,以使其准确地位于您想要的位置。或者这个 LineHeightSpan 有什么问题,看看这个其他答案stackoverflow.com/a/11120208/409695
  • 是的,太棒了!效果很好!!高超!只需注意 setTint() 应该验证要使用的 Android 版本。
  • 添加builder.setSpan(new ForegroundColorSpan(color), 1, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);如果你想要文本的颜色相同
【解决方案7】:

当前最佳,但未被接受 solution 可能适用于旧平台。无论如何,在新的 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);
}

【讨论】:

  • 我不知道你是怎么破坏西蒙的解决方案的,但是method didn't change between Aug 2014-May 2015,它也是sits happily on Android 5.1.1
  • 您是否可能忘记告诉 ProGuard? -keepclassmembers **.MenuBuilder { void setOptionalIconsVisible(boolean); }
  • 嗯,有可能。我通常在未混淆的代码上进行测试,但这是可能的。如果您在 5.x 设备上没有问题,请将其作为另一种替代解决方案,仅此而已。
【解决方案8】:

我找到的最简单的方法是:

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

【讨论】:

    【解决方案9】:

    @Simon 的答案真的很好用...但是你们中的一些人正在使用 AppCompat Activity...您需要改用此代码...因为在 appcompat-v7:22 中不再调用 onMenuOpened() .x

    @Override
        protected boolean onPrepareOptionsPanel(View view, Menu menu) {
            if(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(Constants.DEBUG_LOG, "onMenuOpened", e);
                    }
                    catch(Exception e){
                        throw new RuntimeException(e);
                    }
                }
            }
            return super.onPrepareOptionsPanel(view, menu);
        }
    

    【讨论】:

      【解决方案10】:

      科特林:

      @SuppressLint("RestrictedApi")
      fun Menu.showOptionalIcons() {
          this as MenuBuilder
          setOptionalIconsVisible(true)
      }
      

      【讨论】:

        【解决方案11】:

        Simon 与 ActionMode 一起使用的出色解决方案的简单模型:

         @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                if(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, "onPrepareActionMode", e);
                        }
                        catch(Exception e){
                            throw new RuntimeException(e);
                        }
                    }
                }
                return true;
            }
        

        【讨论】:

          【解决方案12】:

          据我所知,这只能通过创建自定义工具栏来实现。因为默认的 ActionBar 没有为您提供该功能。但是您可以通过将子菜单作为项目的子菜单来放置图标。如果你有比我更好的解决方案.. 告诉我。

          <?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_settings"
              android:icon="@drawable/ic_menu_camera"
              android:showAsAction="never"
              android:title="@string/action_settings" />
          
          <item
              android:id="@+id/action_1"
              android:icon="@drawable/ic_menu_gallery"
              android:showAsAction="never"
              android:title="Hello" />
          
          <item
              android:id="@+id/action_search"
              android:icon="@android:drawable/ic_search_category_default"
              android:showAsAction="never"
              android:title="action_search">
          
              <menu>
                  <item
                      android:id="@+id/version1"
                      android:icon="@android:drawable/ic_dialog_alert"
                      android:showAsAction="never"
                      android:title="Cup cake" />
          
                  <item
                      android:id="@+id/version2"
                      android:icon="@drawable/ic_menu_camera"
                      android:showAsAction="never"
                      android:title="Donut" />
          
          
                  <item
                      android:id="@+id/version3"
                      android:icon="@drawable/ic_menu_send"
                      android:showAsAction="never"
                      android:title="Eclair" />
          
                  <item
                      android:id="@+id/version4"
                      android:icon="@drawable/ic_menu_gallery"
                      android:showAsAction="never"
                      android:title="Froyo" />
              </menu>
          </item>
          </menu> 
          

          【讨论】:

            【解决方案13】:

            这为时已晚,但有人可能会帮助我尝试我从@Desmond Lua 得到帮助答案 这有助于谁使用menu.xml

            我的答案是创建动态菜单,这里是我的代码:

              int ACTION_MENU_ID =1;
              SpannableStringBuilder builder;
               @Override
              public boolean onCreateOptionsMenu(Menu menu) {
            
              //this space for icon 
                builder = new SpannableStringBuilder("  " + getString(R.string.your_menu_title));
                builder.setSpan(new ImageSpan(this,  R.drawable.ic_your_menu_icon), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
              //dynamic menu added 
                menu.add(Menu.NONE,ACTION_MENU_ID, Menu.NONE,
                         getString(R.string.your_menu_title))
                        .setShowAsAction(MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
              //set icon in overflow menu      
                    menu.findItem(ACTION_MENU_ID).setTitle(builder);
            }
            

            【讨论】:

              【解决方案14】:

              在样式中添加这个:

              <menu xmlns:android="http://schemas.android.com/apk/res/android">
                  <item
                      android:id="@+id/action_settings"
                      app:showAsAction="always"
                      android:icon="@drawable/ic_more_vert_white"
                      android:orderInCategory="100"
                      android:title="">
                      <menu>
              
                          <item
                              android:id="@+id/Login"
                              android:icon="@drawable/ic_menu_user_icon"
                              android:showAsAction="collapseActionView|withText"
                              android:title="@string/str_Login" />
              
                          <item
                              android:id="@+id/str_WishList"
                              android:icon="@drawable/ic_menu_wish_list_icon"
                              android:showAsAction="collapseActionView"
                              android:title="@string/str_WishList" />
              
                          <item
                              android:id="@+id/TrackOrder"
                              android:icon="@drawable/ic_menu_my_order_icon"
                              android:showAsAction="collapseActionView"
                              android:title="@string/str_TrackOrder" />
              
                          <item
                              android:id="@+id/Ratetheapp"
                              android:icon="@drawable/ic_menu_rate_the_apps"
                              android:showAsAction="collapseActionView"
                              android:title="@string/str_Ratetheapp" />
              
                          <item
                              android:id="@+id/Sharetheapp"
                              android:icon="@drawable/ic_menu_shar_the_apps"
                              android:showAsAction="collapseActionView"
                              android:title="@string/str_Sharetheapp" />
              
                          <item
                              android:id="@+id/Contactus"
                              android:icon="@drawable/ic_menu_contact"
                              android:showAsAction="collapseActionView"
                              android:title="@string/str_Contactus" />
              
                          <item
                              android:id="@+id/Policies"
                              android:icon="@drawable/ic_menu_policy_icon"
                              android:showAsAction="collapseActionView"
                              android:title="@string/str_Policies" />
                      </menu>
                  </item>
              </menu>
              

              【讨论】:

                【解决方案15】:
                 public void showContextMenuIconVisible(Menu menu){
                    if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
                        try {
                            Field field = menu.getClass().getDeclaredField("mOptionalIconsVisible");
                            field.setAccessible(true);
                            field.setBoolean(menu, true);
                        } catch (Exception ignored) {
                            ignored.printStackTrace();
                        }
                    }
                }
                

                【讨论】:

                  【解决方案16】:

                  我使用了 MashukKhan 的建议,但我始终将持有人项目显示为动作,并使用矢量资产中垂直的更多点作为图标。

                  <item
                      android:orderInCategory="10"
                      android:title=""
                      android:icon="@drawable/ic_more_vert"
                      app:showAsAction="always" >
                  
                      <menu>
                          <item
                              android:id="@+id/action_tst1"
                              ...and so on
                  
                     </menu>
                  </item>
                  

                  这会产生“溢出”菜单效果并在下拉菜单中显示图标。
                  如果项目与显示不冲突,甚至可以将项目放在它前面。
                  我发现 MashukKhan 的解决方案很优雅,它适合解决方案而不是解决类别,因为它只是子菜单的实现。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-11-29
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多