Cómo forzar el uso del menú de desbordamiento en los dispositivos con el botón de menú

Me gustaría que todos los elementos del menú que no encajan en la Barra de acciones entren en el menú de desbordamiento (el que se accede desde la Barra de acciones, no el botón de menú), incluso en dispositivos que tienen un botón de Menú . Esto parece mucho más intuitivo para los usuarios que lanzarlos a una lista de menú separada que requiere que el usuario salte de una interacción táctil (pantalla) a una interacción basada en botones simplemente porque el diseño de la barra de acciones no puede encajar en la barra.

En el emulador puedo establecer el valor “Hardware Back / Home Keys” en “no” y obtener este efecto. He buscado una forma de hacer esto en el código de un dispositivo real que tiene un botón de menú pero no puede corregirlo. ¿Alguien puede ayudarme?

EDITAR: modificado para responder a la situación del botón de menú físico.

Esto es realmente prevenido por diseño. De acuerdo con la Sección de Compatibilidad de la Guía de Diseño de Android ,

“… el desbordamiento de acción está disponible desde la tecla de hardware del menú. Las acciones emergentes resultantes … se muestran en la parte inferior de la pantalla”.

Notará en las capturas de pantalla que los teléfonos con un botón de menú físico no tienen un menú de desbordamiento en la barra de acciones. Esto evita ambigüedades para el usuario, teniendo esencialmente dos botones disponibles para abrir exactamente el mismo menú.

Para abordar el problema de la coherencia en todos los dispositivos: en última instancia, para el usuario es más importante que su aplicación se comporte de forma coherente con todas las demás aplicaciones del mismo dispositivo, en lugar de comportarse de forma coherente consigo misma en todos los dispositivos.

También puedes usar este pequeño truco aquí:

try { ViewConfiguration config = ViewConfiguration.get(this); Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey"); if (menuKeyField != null) { menuKeyField.setAccessible(true); menuKeyField.setBoolean(config, false); } } catch (Exception ignored) { } 

Un buen lugar para ponerlo sería el onCreate de su clase de aplicación.

Obligará a la aplicación a mostrar el menú de desbordamiento. El botón de menú seguirá funcionando, pero abrirá el menú en la esquina superior derecha.

[Editar] Ya se ha presentado varias veces: este truco solo funciona para la barra de herramientas nativa introducida en Android 3.0, no en ActionBarSherlock. Este último usa su propia lógica interna para decidir si mostrar el menú de desbordamiento. Si usa ABS, todas las plataformas <4.0 son manejadas por ABS y, por lo tanto, están sujetas a su lógica. El truco seguirá funcionando para todos los dispositivos con Android 4.0 o superior (puede ignorar con seguridad Android 3.x, ya que en realidad no hay ninguna tableta con un botón de menú).

Existe un ForceOverflow-Theme especial que forzará el menú en ABS, pero aparentemente se eliminará en futuras versiones debido a complicaciones .

Utilizo para solucionarlo definiendo mi menú de esta manera (también con el icono de ActionBarSherlock utilizado en mi ejemplo):

         

Admito que esto puede requerir una “gestión de desbordamiento” manual en su xml, pero esta solución me resultó útil.

También puede forzar que el dispositivo use el botón HW para abrir el menú de desbordamiento en su actividad:

 private Menu mainMenu; @Override public boolean onCreateOptionsMenu(Menu menu) { // TODO: init menu here... // then: mainMenu=menu; return true; } @Override public boolean onKeyUp(int keycode, KeyEvent e) { switch(keycode) { case KeyEvent.KEYCODE_MENU: if (mainMenu !=null) { mainMenu.performIdentifierAction(R.id.menu_overflow, 0); } } return super.onKeyUp(keycode, e); } 

🙂

Si está utilizando la barra de acciones de la biblioteca de soporte ( android.support.v7.app.ActionBar ), use lo siguiente:

 < ?xml version="1.0" encoding="utf-8"?>         

Este tipo de método es prevenido por el Sistema de Diseño de Desarrolladores de Android, pero encontré una manera de pasarlo:

Agregue esto a su archivo de menú XML:

  

Luego, crea una clase llamada ‘AppPickActionProvider’ y copia el siguiente código:

  package com.example; import android.content.Context; import android.util.Log; import android.view.ActionProvider; import android.view.MenuItem; import android.view.MenuItem.OnMenuItemClickListener; import android.view.SubMenu; import android.view.View; public class AppPickActionProvider extends ActionProvider implements OnMenuItemClickListener { static final int LIST_LENGTH = 3; Context mContext; public AppPickActionProvider(Context context) { super(context); mContext = context; } @Override public View onCreateActionView() { Log.d(this.getClass().getSimpleName(), "onCreateActionView"); return null; } @Override public boolean onPerformDefaultAction() { Log.d(this.getClass().getSimpleName(), "onPerformDefaultAction"); return super.onPerformDefaultAction(); } @Override public boolean hasSubMenu() { Log.d(this.getClass().getSimpleName(), "hasSubMenu"); return true; } @Override public void onPrepareSubMenu(SubMenu subMenu) { Log.d(this.getClass().getSimpleName(), "onPrepareSubMenu"); subMenu.clear(); subMenu.add(0, 1, 1, "Item1") .setIcon(R.drawable.ic_action_home).setOnMenuItemClickListener(this); subMenu.add(0, 2, 1, "Item2") .setIcon(R.drawable.ic_action_downloads).setOnMenuItemClickListener(this); } @Override public boolean onMenuItemClick(MenuItem item) { switch(item.getItemId()) { case 1: // What will happen when the user presses the first menu item ( 'Item1' ) break; case 2: // What will happen when the user presses the second menu item ( 'Item2' ) break; } return true; } } 

Bueno, creo que Alexander Lucas ha proporcionado la (desafortunadamente) respuesta correcta, así que la estoy marcando como la “correcta”. La respuesta alternativa que estoy agregando aquí es simplemente apuntar a cualquier lector nuevo a esta publicación en el blog de Desarrolladores de Android como una discusión más completa del tema con algunas sugerencias específicas sobre cómo lidiar con tu código cuando pases del nivel anterior al 11 a la nueva barra de acción.

Todavía creo que fue un error de diseño no tener el botón de menú comportarse como un botón redundante de “Acción desbordada” en los dispositivos habilitados con el botón de menú como una mejor forma de transición de la experiencia del usuario pero su agua debajo del puente en este punto.

No estoy seguro de si esto es lo que estás buscando, pero construí un Submenú dentro del Menú de la Barra de Acción y configuré su ícono para que coincida con el Ícono del Menú de Desbordamiento. Aunque no le enviarán elementos automáticamente (es decir, debe elegir lo que siempre está visible y lo que siempre se desborda), me parece que este enfoque puede ayudarlo.

En la aplicación de Gmail que viene con ICS preinstalado, el botón del menú se desactiva cuando tiene múltiples elementos seleccionados. El menú de desbordamiento está aquí “forzado” para activarse mediante el uso del botón de desbordamiento en lugar del botón de menú físico. Hay una lib de terceros llamada ActionBarSherlock que te permite “forzar” el menú de desbordamiento. Pero esto solo funcionará en API nivel 14 o inferior (pre-ICS)

Si usa la barra de herramientas , puede mostrar el desbordamiento en todas las versiones y todos los dispositivos, lo he probado en algunos dispositivos 2.x, funciona.

Lo siento si este problema está muerto.

Esto es lo que hice para resolver el error. Fui a diseños y creé dos que contenían barras de herramientas. Uno era un diseño para la versión sdk 8 y el otro era para la versión sdk 21. En la versión 8, utilicé android.support.v7.widget.Toolbar mientras usaba android.widget.Toolbar en el diseño de sdk 21.

Luego infló la barra de herramientas en mi actividad. Verifico el SDK para ver si era 21 o más. Luego inflico el diseño correspondiente. Esto fuerza que el botón de hardware se asigne a la barra de herramientas que diseñó en realidad.

Para cualquiera que use la nueva Toolbar :

 private Toolbar mToolbar; @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); mToolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(mToolbar); ... } @Override public boolean onKeyUp(int keycode, KeyEvent e) { switch(keycode) { case KeyEvent.KEYCODE_MENU: mToolbar.showOverflowMenu(); return true; } return super.onKeyUp(keycode, e); }