¿Cómo actualizar un elemento de menú que se muestra en ActionBar?

93

Tengo una actividad que tiene 2 fragmentos. Ambos son ListFragments y ambos contribuyen MenuItems al Menú. Tengo un MenuItem que configuré el atributo android: showAsAction para que se muestre como un botón en ActionBar. Que funciona bien.

Ahora MenuItem depende del estado. Es una opción de menú Pausar / Reanudar para pausar y reanudar una cola. Mi problema es que no puedo averiguar cómo colocar su estatua inicial cuando se crea el Fragmento.

Su estado depende de si la cola está en pausa o no. Entonces tengo un AsyncTask que obtiene la cola y establece un booleano (en pausa) basado en el estado de la cola. Estoy llamando a onPrepareOptionsMenu para configurar el texto para el elemento del menú Pausa en función del último estado conocido de la cola y esto funciona muy bien si dejo MenuItem en el menú real. Toca el icono de menú y onPrepareOptionsMenu se activa y el menú se actualiza antes de que se muestre.

El problema es que si coloco ese mismo MenuItem en ActionBar (showAsAction), ¿cómo puedo forzarlo a actualizar sin tener que llamar a onPrepareOptionsMenu? Necesito poder hacer esto porque en el primer lanzamiento de la aplicación, envío una solicitud para obtener la cola, pero la tarea regresa después de que se configura y muestra la barra de acciones. Creé un controlador en mi fragmento que se llama cada vez que obtengo una actualización de la cola, pero a partir de ahí, ¿cómo puedo actualizar el texto de mi MenuItem en la barra de acciones? Parece que no puedo encontrar una manera de hacer que el menú configurado actualmente lo manipule, excepto en onPrepareOptionMenu.

Rob W.

brócoli
fuente

Respuestas:

174

Opción # 1: Prueba invalidateOptionsMenu(). No sé si esto forzará un redibujo inmediato de la barra de acción o no.

Opción # 2: Vea si getActionView()devuelve algo para el afectado MenuItem. Es posible que showAsActionsimplemente cree automáticamente vistas de acciones para usted. Si es así, presumiblemente puede habilitarlo / deshabilitarlo View.

Parece que no puedo encontrar una manera de hacer que el menú configurado actualmente lo manipule, excepto en onPrepareOptionMenu.

Puede colgarse del Menuobjeto que le entregaron onCreateOptionsMenu(). Citando los documentos :

Puede mantener de forma segura el menú (y cualquier elemento creado a partir de él), realizando las modificaciones que desee, hasta la próxima vez que se llame a onCreateOptionsMenu ().

CommonsWare
fuente
2
Probé la Opción # 1 y esto funcionó. Como estaba tratando de actualizar la interfaz de usuario en una devolución de llamada desde un hilo separado, estaba lanzando una excepción ya que en realidad no estaba en el hilo de la interfaz de usuario. Para solucionar este problema, creé un controlador y envié un mensaje de actualización al controlador cuando se llamó a mi devolución de llamada. Pero finalmente usé getActivity (). InvalidateOptionsMenu () para actualizar el menú.
brócoli
@brockoli: ¡Ah, bien! Dada la redacción de los Javadocs para ese método, era escéptico de que tuviera el efecto deseado, aunque parece que fue la razón por la que lo agregaron al nivel de API 11 en primer lugar. ¡Me alegra saber que está funcionando para usted!
CommonsWare
¡Me he estado golpeando la cabeza contra la pared tratando de resolver esto y funciona como un encanto!
MinceMan
7
Si está utilizando la biblioteca de soporte, use supportInvalidateOptionsMenu()en su lugar
Tim Kist
2
@TimKist, supportInvalidateOptionsMenu()ahora está en desuso; puede utilizar de forma segura invalidateOptionsMenu().
Primož Kralj
12

en mi caso: invalidateOptionsMenusimplemente restablecí el texto al original, pero accediendo directamente al elemento del menú y reescribiendo el texto deseado funcionó sin problemas:

if (mnuTopMenuActionBar_ != null) {
    MenuItem mnuPageIndex = mnuTopMenuActionBar_
        .findItem(R.id.menu_magazin_pageOfPage_text);

    if (mnuPageIndex != null) {
        if (getScreenOrientation() == 1) {
            mnuPageIndex.setTitle((i + 1) + " von " + pages);
        }
        else {
            mnuPageIndex.setTitle(
                (i + 1) + " + " + (i + 2) + " " + " von " + pages);
        }
        // invalidateOptionsMenu();
    }
}

debido al comentario a continuación, pude acceder al elemento del menú a través del siguiente código:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.magazine_swipe_activity, menu);
    mnuTopMenuActionBar_ = menu;
    return true;
}
cV2
fuente
¿Cómo manejaste la vista ActionBar con mnuTopMenuActionBar_?
Paul Mennega
1
cuando la barra de acción se inicializa, guardé la vista en una variable miembro ... así: @Override public boolean onCreateOptionsMenu (menú Menú) {MenuInflater inflater = getMenuInflater (); inflater.inflate (R.menu.magazine_swipe_activity, menú); mnuTopMenuActionBar_ = menú; devuelve verdadero; }
cV2
Al hacer eso, puede tener problemas de sincronización, ¿verdad? Quiero decir. no sabe EXACTAMENTE cuándo se ejecutará onCreateOptionMenu, por lo que puede llegar a su fragmento de código con el mnuTopMenuActionBar_no inicializado, ¿verdad? ¿Cómo solucionaría eso?
acrespo
oye, si se usa la barra de acción (sí, aquí está), este método siempre se llama, por lo que no hay problema con eso ... (directamente al inicio de la actividad) stackoverflow.com/questions/7705927/…
cV2
11

Para actualizar el menú desde Fragment simplemente llame a:

getActivity().invalidateOptionsMenu();
CoolMind
fuente
4

He usado este código:

public boolean onPrepareOptionsMenu (Menu menu) {       
    MenuInflater inflater = getMenuInflater();
    TextView title  = (TextView) findViewById(R.id.title);
    menu.getItem(0).setTitle(
        getString(R.string.payFor) + " " + title.getText().toString());
    menu.getItem(1).setTitle(getString(R.string.payFor) + "...");
    return true;        
}

Y funcionó como un encanto para mí, puedes encontrar OnPrepareOptionsMenu aquí

PEDIR
fuente
4
¿Cuál es el propósito de MenuInflater aquí?
IgorGanapolsky
Esto es brillante
Steve Kamau
2

Primero, siga las dos líneas de códigos para actualizar los elementos de la barra de acciones antes de establecer una condición en oncreateOptionMenu (). Por ejemplo:

Boolean mISQuizItemSelected = false;

/**
 * Called to inflate the action bar menus
 *
 * @param menu
 *      the menu
 *
 * @return true, if successful
 */

@Override
public boolean onCreateOptionsMenu(Menu menu) {

    // Inflate the menu items for use in the action bar

    inflater.inflate(R.menu.menu_demo, menu);

    //condition to hide the menus
    if (mISQuizItemSelected) {
        for (int i = 0; i < menu.size(); i++) {
            menu.getItem(i).setVisible(false);
        }
    }

    return super.onCreateOptionsMenu(menu);
}

/**
 * Called when the item on the action bar being selected.
 *
 * @param item
 *      menuitem being selected
 *
 * @return true if the menuitem id being selected is matched
 * false if none of the menuitems id are matched
 */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getId() == R.id.action_quiz) {
        //to navigate based on the usertype either learner or leo
        mISQuizItemSelected = true;

        ActionBar actionBar = getActionBar();
        invalidateOptionMenu();
    }
}
saranya
fuente
1

Para mayor claridad, pensé que a continuación se puede mostrar un ejemplo directo de apropiación de un recurso que creo que contribuye a la respuesta a esta pregunta con un ejemplo directo rápido.

private MenuItem menuItem_;

@Override
public boolean onCreateOptionsMenu(Menu menuF) 
{
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_layout, menuF);
    menuItem_ = menuF.findItem(R.id.menu_item_identifier);
    return true;
}

En este caso, mantiene una referencia de MenuItem al principio y luego cambia su estado (para cambios de estado de icono, por ejemplo) en un momento dado posterior.

Jay Snayder
fuente
-1

En Kotlin 1.2 simplemente llame a:

invalidateOptionsMenu()

y se onCreateOptionsMenuvolverá a llamar a la función.

j_gonfer
fuente