Cómo mostrar icons en el menú Desbordamiento en ActionBar

Sé que no es posible usar la API nativa. ¿Hay alguna solución para implementar ese tipo de vista?

La respuesta publicada anteriormente está bien, en términos generales. Pero básicamente elimina el comportamiento predeterminado del menú Desbordamiento. Cosas como la cantidad de icons que se pueden mostrar en diferentes tamaños de pantalla y luego caen en el menú de desbordamiento cuando no se pueden mostrar. Al hacer lo anterior, elimina una gran cantidad de funcionalidades importantes.

Un mejor método sería decirle al menú de desbordamiento que muestre los íconos directamente. Puedes hacer esto agregando el siguiente código a tu Actividad.

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

En su menú xml, use la siguiente syntax para anidar el menú, comenzará a obtener el menú con icons

      

Probé esto en base a las respuestas anteriores y funciona bien, al menos con las versiones más recientes de la biblioteca de soporte (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; } 

Puede hacer uso de 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); } 

La respuesta de Simon fue muy útil para mí, así que quiero compartir cómo la implementé en el método onCreateOptionsMenu como se sugiere:

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

Sobre la base de la respuesta de @Desmond Lua desde arriba , hice un método estático para usar el dibujo declarado en XML en el menú desplegable y asegurándome de que su color tintado no afecta el estado de dibujo constante.

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

Y usarlo se vería algo así cuando se usa en una actividad. Esto podría ser aún más elegante dependiendo de sus necesidades individuales.

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

La mejor solución actual, pero no aceptada , probablemente funcione en plataformas más antiguas. De todos modos, en el nuevo AppCompat21 +, el método requerido no existe y el método getDeclaredMethod devuelve la excepción NoSuchMethodException .

Así que la solución para mí (probada y funcionando en dispositivos 4.x, 5.x) se basa en el parámetro de fondo de cambio directo. Así que simplemente coloque este código en su clase de Actividad.

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

La respuesta de @Simon realmente funciona bien … pero usted está usando AppCompat Activity … necesitará usar este código en su lugar … Porque onMenuOpened () ya no se llama en 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); } 

Según yo, esto solo es posible creando una barra de herramientas personalizada. Debido a que ActionBar por defecto no le da esa característica. Pero puede poner icons tomando el submenú como elemento secundario de un elemento. Y si tienes una mejor solución que yo … solo infórmame.

              

Mi mod simple a la excelente solución de Simon para usar con 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; } 

Esto es demasiado tarde, pero alguien puede ayudarme a intentarlo. Obtuve la ayuda de la respuesta de @Desmond Lua que ayuda a quien usa menu.xml

Mi respuesta es para la creación de menú dynamic aquí está mi código:

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

Agregue esto en estilo:

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