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

我知道使用本地API是不可能的。 有没有解决scheme来实现这种观点?

以前张贴的答案是好的,一般来说。 但它基本上删除了溢出菜单的默认行为。 比如有多less图标可以显示在不同的屏幕尺寸上,然后在不能显示的时候丢到溢出菜单中。 通过执行上述操作,您可以删除许多重要的function。

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

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

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

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

试过这个基于以前的答案,它工作正常,至less与更新版本的支持库(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; } 

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

在上面的@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); } } 

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

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

目前最好的,但不被接受的解决scheme可能适用于较旧的平台 无论如何,在新的AppCompat21 +,所需的方法不存在和方法getDeclaredMethod返回exceptionNoSuchMethodException

所以我的解决方法(testing和工作在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); } 

@Simon的答案确实很好…但是你使用AppCompat Activity …你将需要使用这个代码…因为在appcompat-v7中不会调用onMenuOpened():22.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); } 

根据我这只能通过创build一个自定义工具栏。 因为默认的ActionBar不给你这个function。 但是可以通过将子菜单作为项目的子项来放置图标。 如果你有比我更好的解决scheme,请告诉我。

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

我简单的mod到Simon用ActionMode的优秀解决scheme:

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

这太晚了,但有些人可能会帮助我尝试从@Desmond Lua得到帮助,帮助谁使用menu.xml

我的答案是dynamic菜单创build这里是我的代码:

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

添加样式:

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