Как показать значки в меню переполнения в ActionBar

Я знаю, что это невозможно, используя собственный API. Есть ли способ обхода такого вида?

Solutions Collecting From Web of "Как показать значки в меню переполнения в ActionBar"

Ответ, который был ранее опубликован, в общем-то в порядке. Но в основном это устраняет поведение по умолчанию меню переполнения. Такие вещи, как количество значков могут отображаться на разных размерах экрана, а затем они выпадали в меню переполнения, когда они не могут отображаться. Делая вышеизложенное, вы удаляете множество важных функций.

Лучшим способом было бы указать меню переполнения для отображения значков напрямую. Вы можете сделать это, добавив следующий код в свою деятельность.

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

Пробовал это на основе предыдущих ответов, и он отлично работает, по крайней мере, с более поздними версиями библиотеки поддержки (25.1):

 @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); if(menu instanceof MenuBuilder){ MenuBuilder m = (MenuBuilder) menu; m.setOptionalIconsVisible(true); } return true; } 

Ответ от Саймона был очень полезен для меня, поэтому я хочу поделиться тем, как я реализовал его в onCreateOptionsMenu как это было предложено:

 @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 сверху , я сделал статический метод для использования drawable, объявленного в XML в раскрывающемся списке, и чтобы его тонированный цвет не влиял на состояние 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; } 

Самое лучшее, но не принятое решение, вероятно, работает на более старых платформах. В любом случае в новом 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); } 

Ответ @Simon действительно хорошо работает … но вы используете AppCompat Activity … вам нужно будет использовать этот код … Потому что onMenuOpened () больше не вызывается в appcompat-v7: 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); } 

По моему мнению, это возможно только при создании пользовательской панели инструментов. Поскольку 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> 

Мой простой мод для превосходного решения 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; } 

Это слишком поздно, но кто-то может помочь в моей попытке получить помощь от ответа @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); } 

Добавьте это в стиле:

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