Cómo agregar un menú de opciones a Fragment en Android


399

Estoy tratando de agregar un elemento al menú de opciones desde un grupo de fragmentos.

He creado una nueva MenuFragmentclase y la extendí para los fragmentos en los que deseo incluir el elemento del menú. Aquí está el código:

Java:

public class MenuFragment extends Fragment {

    MenuItem fav;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        fav = menu.add("add");
        fav.setIcon(R.drawable.btn_star_big_off);
    }
}

Kotlin:

class MenuFragment : Fragment {

    lateinit var fav: MenuItem

    override fun onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        fav = menu.add("add");
        fav.setIcon(R.drawable.btn_star_big_off);
    }
}

Por alguna razón, onCreateOptionsMenuparece que no se ejecuta.


tal vez una pregunta tonta ... presionas el botón de menú ¿verdad?
Ovidiu Latcu

2
..lol ... sí, he presionado el botón de menú, también lo he intentado con y sin: fav.setShowAsAction (MenuItem.SHOW_AS_ACTION_ALWAYS);
misterbassman

Hola, tal vez este hilo lo ayude o consulte la demostración de la API para ver un ejemplo de trabajo.
kameny

Respuestas:


605

Llame al súper método:

Java:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // TODO Add your menu entries here
        super.onCreateOptionsMenu(menu, inflater);
    }

Kotlin:

    override fun void onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        // TODO Add your menu entries here
        super.onCreateOptionsMenu(menu, inflater)
    }

Ponga declaraciones de registro en el código para ver si no se está llamando al método o si el código no está modificando el menú.

También asegúrese de que está llamando setHasOptionsMenu(boolean)en onCreate(Bundle)notificar el fragmento que debe participar en el manejo del menú Opciones.


2
Gracias por la ayuda, agregué el súper método y me di cuenta de que había eliminado el @Override, así que lo agregué nuevamente, eclipse arrojó un error, así que reemplacé el MenuInflater para importar android.view.MenuInflater; en lugar de importar android.support.v4.view.MenuInflater; y ahora todo funciona
misterbassman

183
no llamar a setHasOptionsMenu (verdadero) en onCreate del Fragmento me ha atrapado dos veces ahora
joshkendrick

77
Estaba transfiriendo mi Actividad a un Fragmento y me encontré con este problema. La firma del método ha cambiado de public boolean a public void y los argumentos también han cambiado. ¡Asegúrate de tomar nota de esto!
you786

14
Tenga en cuenta que Fragment.onCreateOptionsMenu (Menu, MenuInflater) es un método vacío, por lo que no es necesario llamar a super. El único error aquí fue la firma del método incorrecto y posiblemente un setHasOptionsMenu () faltante en onCreate ()
cmende

66
Reemplace super.onCreateOptionsMenu con inflater.inflate (R.menu.menu_custom, menu);
Code_Worm

197

Tuve el mismo problema, pero creo que es mejor resumir e introducir el último paso para que funcione:

  1. Agregue el método setHasOptionsMenu (verdadero) en el método de su Fragmento onCreate(Bundle savedInstanceState).

  2. Anular onCreateOptionsMenu(Menu menu, MenuInflater inflater)(si desea hacer algo diferente en el menú de su Fragmento) y onOptionsItemSelected(MenuItem item)métodos en su Fragmento.

  3. Dentro onOptionsItemSelected(MenuItem item)del método de su Actividad, asegúrese de devolver falso cuando la acción del elemento del menú se implementaría en onOptionsItemSelected(MenuItem item)el método de Fragment.

Un ejemplo:

Actividad

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getSupportMenuInflater();
    inflater.inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.activity_menu_item:

            // Do Activity menu item stuff here
            return true;

        case R.id.fragment_menu_item:

            // Not implemented here
            return false;
        default:
            break;
    }

    return false;
}

Fragmento

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    ....
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // Do something that differs the Activity's menu here
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.activity_menu_item:

            // Not implemented here
            return false;
        case R.id.fragment_menu_item:

            // Do Fragment menu item stuff here
            return true;

        default:
            break;
    }

    return false;
}

2
Solo faltaba setHasOptionsMenu(true);Gracias
Chad Bingham

1
En un viewPager en algunos dispositivos, el menú solo se muestra la segunda vez que va al fragmento
Roel

3
@Marco HC su código funciona bien. Pero, ¿qué sucede si quiero ocultar parte del menú de Actividad o Fragmento? Ha mencionado dónde implementar qué menú de opciones (En actividad y fragmento). ¿Pero qué pasa si quiero ocultar algún menú?
Shreyash Mahajan

@iDroidExplorer solo mantiene una referencia a ese MenuItem y configura la visibilidad como desaparecida o invisible. ¿Esa es tu pregunta?
Marco HC

@iDroidExplorer Probé su código y no sé cómo, pero oculta automáticamente el menú cuando cambio a otros fragmentos.
Noor Ali Butt

156

Si encuentra que el onCreateOptionsMenu(Menu menu, MenuInflater inflater)método no se invoca, asegúrese de llamar a lo siguiente desde el onCreate(Bundle savedInstanceState)método Fragment :

setHasOptionsMenu(true)

Me da un error como NullPointerException
Pratik Butani

2
Buen punto. Estaba llamando al método setHasOptionMenu desde el método estático newInstance. Como solo estaba adjuntando mi fragmento cuando saveInstanceState era nulo, cuando la configuración de la pantalla cambiaba, no se creaba el menú. El método onCreate del fragmento es el lugar correcto donde establecer setHasOptionMenu en verdadero.
argenkiwi

1
Estoy usando una Toolbary tuvo que llamar setHasOptionsMenu(true)en onCreateView()su lugar onCreate()para hacerlo.
CLOUGH

60

Si necesita un menupara actualizar un webviewdentro de un específico Fragment, puede usar:

Fragmento :

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

    // TODO Add your menu entries here
    inflater.inflate(R.menu.menu, menu);
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.exit:
        System.exit(1);
        break;

    case R.id.refresh:
        webView.reload();
        break;
    }
    return true;

}

menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/exit" android:title="Exit" android:icon="@drawable/ic_action_cancel" />
    <item android:id="@+id/refresh" android:title="Refresh" android:icon="@drawable/ic_action_refresh" />
</menu>

31

TL; DR

Use android.support.v7.widget.Toolbary simplemente haga:

toolbar.inflateMenu(R.menu.my_menu)
toolbar.setOnMenuItemClickListener {
    onOptionsItemSelected(it)
}

Barra de herramientas independiente

La mayoría de las soluciones sugeridas como setHasOptionsMenu(true)solo funcionan cuando la Actividad principal tiene la Barra de herramientas en su diseño y la declara a través de setSupportActionBar(). Entonces los Fragmentos pueden participar en la población del menú de este ActionBar exacto :

Fragment.onCreateOptionsMenu (): Inicializa el contenido del menú de opciones estándar del host Fragment.

Si desea una barra de herramientas independiente y un menú para un Fragmento específico , puede hacer lo siguiente:

menu_custom_fragment.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_save"
        android:title="SAVE" />
</menu>

custom_fragment.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    ...

CustomFragment.kt

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view = inflater.inflate(layout.custom_fragment, container, false)
    val toolbar = view.findViewById<Toolbar>(R.id.toolbar)
    toolbar.inflateMenu(R.menu.menu_custom_fragment)
    toolbar.setOnMenuItemClickListener {
        onOptionsItemSelected(it)
    }
    return view
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.menu_save -> {
            // TODO: User clicked the save button
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Sí, es así de fácil. Ni siquiera necesita anular onCreate()o onCreateOptionsMenu().

PD: Esto solo funciona con android.support.v4.app.Fragmenty android.support.v7.widget.Toolbar(también asegúrese de usar AppCompatActivityy un AppCompattema en su styles.xml).


1
realmente me ayudó mucho
brahmy adigopula

23

En el menu.xmldebe agregar todos los elementos del menú. Luego, puede ocultar elementos que no desea ver en la carga inicial.

menu.xml

<item
    android:id="@+id/action_newItem"
    android:icon="@drawable/action_newItem"
    android:showAsAction="never"
    android:visible="false"
    android:title="@string/action_newItem"/>

Agregue setHasOptionsMenu(true)el método onCreate () para invocar los elementos del menú en su clase Fragment.

FragmentClass.java

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

No necesita anular onCreateOptionsMenunuevamente en su clase Fragment. Los elementos del menú se pueden cambiar (Agregar / quitar) anulando el onPrepareOptionsMenumétodo disponible en Fragmento.

@Override
public void onPrepareOptionsMenu(Menu menu) {
    menu.findItem(R.id.action_newItem).setVisible(true);
    super.onPrepareOptionsMenu(menu);

}

16

Debe usar menu.clear () antes de inflar menús.

@Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        menu.clear();
        inflater.inflate(R.menu.menu, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

y

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

1
Esto es correcto cuando desea diferentes menús en diferentes fragmentos y está agregando fragmentos en lugar de reemplazarlos.
Akshay Mahajan

¡Gracias! menu.clear () me ayuda a eliminar la opción de menú de Actividad.
kimcy929

13

En mi caso, aquí están los pasos.

Paso 1

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Here notify the fragment that it should participate in options menu handling.
    setHasOptionsMenu(true);
}

Paso 2

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // First clear current all the menu items
    menu.clear();

    // Add the new menu items
    inflater.inflate(R.menu.post_stuff, menu);

    super.onCreateOptionsMenu(menu, inflater);
}

Paso 3

 @Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.post_stuff:
            Log.d(TAG, "Will post the photo to server");
            return true;
        case R.id.cancel_post:
            Log.d(TAG, "Will cancel post the photo");
            return true;
        default:
            break;
    }
    return super.onOptionsItemSelected(item);
}

Ya tenía un menú en la actividad principal, usando el menu.clear()menú anterior despejado. Trabajó para mí :)
Anbuselvan Rocky

8

Si quieres agregar tu menú personalizado

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_custom, menu);
}

¿Qué sucede si hay una vista de pestaña y desea inflar diferentes menús para cada fragmento?
Jainam Jhaveri

7

He tenido el mismo problema, mis fragmentos eran páginas de un ViewPager. La razón por la que sucedía es que estaba usando el administrador de fragmentos hijo en lugar del administrador de fragmentos de soporte de actividad al crear instancias de FragmentPagerAdapter.


3

Archivo de menú:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/play"
        android:titleCondensed="Speak"
        android:showAsAction="always"
        android:title="Speak"
        android:icon="@drawable/ic_play">
    </item>
    <item
        android:id="@+id/pause"
        android:titleCondensed="Stop"
        android:title="Stop"
        android:showAsAction="always"
        android:icon="@drawable/ic_pause">
    </item>
</menu>

Código de actividad:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.speak_menu_history, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.play:
            Toast.makeText(getApplicationContext(), "speaking....", Toast.LENGTH_LONG).show();
            return false;

        case R.id.pause:
            Toast.makeText(getApplicationContext(), "stopping....", Toast.LENGTH_LONG).show();
            return false;

        default:
            break;
    }

    return false;
}

Código de fragmento:

@Override

public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.play:
            text = page.getText().toString();
            speakOut(text);

            // Do Activity menu item stuff here
            return true;

        case R.id.pause:
            speakOf();

            // Not implemented here
            return true;

        default:
            break;
    }
    return false;
}

3

Tu código está bien. Solo faltaba el super en el método:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // TODO add your menu : 
    inflater.inflate(R.menu.my_menu, menu);
    //TODO call super
    super.onCreateOptionsMenu(menu, inflater);
}

2

Me estaba volviendo loco porque ninguna de las respuestas aquí funcionó para mí.

Para mostrar el menú tuve que llamar: setSupportActionBar(toolbar)

¡Hecho!

Nota: si su toolbarvista no está en el mismo diseño de actividad, no puede usar la llamada anterior directamente desde su clase de actividad, en este caso deberá obtener esa actividad de su clase de fragmento y luego llamar alsetSupportActionBar(toolbar) . Recordando: su clase de actividad debería extender AppCompatActivity.

Espero que esta respuesta te ayude.


1

Configurar el menú de opciones después de crear la vista de fragmentos funcionó bien para mí.

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setHasOptionsMenu(true);        
}

1

Mi problema fue un poco diferente. Hice todo bien. Pero estaba heredando la clase incorrecta para la actividad que aloja el fragmento.

Para que quede claro, si está anulando onCreateOptionsMenu(Menu menu, MenuInflater inflater)el fragmento, asegúrese de que su clase de actividad que aloja este fragmento heredaandroid.support.v7.app.ActionBarActivity (en caso de que desee admitir un nivel de API inferior al 11).

Estaba heredando android.support.v4.app.FragmentActivitypara admitir el nivel de API por debajo de 11.


1

Una cosa que agregaría a esto y la razón por la que no funcionaba para mí.

Es similar a la respuesta de Napster.

  1. ¡Asegúrate de que la actividad de alojamiento de tu fragmento se extienda AppCompatActivity, no FragmentActivity!

    public class MainActivity extends AppCompatActivity {
    
    }

    De la documentación de referencia de Google para FragmentActivity:

    Nota: Si desea implementar una actividad que incluya una barra de acción, debe usar la clase ActionBarActivity, que es una subclase de esta, por lo que le permite usar API Fragment en el nivel API 7 y superior.

  2. Para actualizar la respuesta de Napster, ActionBarActivityahora en desuso, use AppCompatActivityen su lugar.

  3. Cuando lo use AppCompatActivity, también asegúrese de establecer "el tema de la actividad en Theme.AppCompatun tema similar" (Google Doc).

Nota: android.support.v7.app.AppCompatActivityes una subclase de la android.support.v4.app.FragmentActivityclase (consulte el documento de referencia AppCompatActivity ).


1

En su carpeta de menú, haga un archivo .menu xml y agregue este xml

<item
    android:id="@+id/action_search"
    android:icon="@android:drawable/ic_menu_search"
    android:title="@string/action_search"
    app:actionViewClass="android.support.v7.widget.SearchView"
    app:showAsAction="always|collapseActionView" />

En su clase de fragmentos, anule este método y

implement SearchView.OnQueryTextListener    in your fragment class



@Override
 public void onViewCreated(View view, Bundle savedInstanceState) {    
  super.onViewCreated(view, savedInstanceState);
  setHasOptionsMenu(true);

}

Ahora solo configure su archivo xml de menú en clase de fragmento

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_main, menu);

    final MenuItem item = menu.findItem(R.id.action_search);
    final SearchView searchView = (SearchView)    
    MenuItemCompat.getActionView(item);


    MenuItemCompat.setOnActionExpandListener(item,
            new MenuItemCompat.OnActionExpandListener() {
                @Override
                public boolean onMenuItemActionCollapse(MenuItem item) {
                    // Do something when collapsed

                    return true; // Return true to collapse action view
                }

                @Override
                public boolean onMenuItemActionExpand(MenuItem item) {
                    // Do something when expanded
                    return true; // Return true to expand action view
                }
            });

}

0

Si todo lo anterior no funciona, debe depurar y asegurarse de que se haya llamado a la función onCreateOptionsMenu (colocando el registro de depuración o escritura ...)

Si no se ejecuta, tal vez su tema de Android no sea compatible con la barra de acción. Abra AndroidManifest.xml y establezca el valor android:themecon la barra de acción de soporte de temas :

 <activity
     android:name=".MainActivity"
     android:label="@string/app_name"
     android:theme="@style/Theme.AppCompat">

0

en su onCreate método add setHasOptionMenu ()

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

Luego anule su onCreateOptionsMenu

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.add("Menu item")
            .setIcon(android.R.drawable.ic_delete)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.