Comment ajouter un menu d'options à Fragment dans Android

399

J'essaie d'ajouter un élément au menu d'options à partir d'un groupe de fragments.

J'ai créé une nouvelle MenuFragmentclasse et l'ai étendue aux fragments dans lesquels je souhaite inclure l'élément de menu. Voici le code:

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

Pour une raison quelconque, le onCreateOptionsMenusemble ne pas fonctionner.

monsieurbassman
la source
peut-être une question stupide ... vous appuyez sur le bouton de menu à droite?
Ovidiu Latcu
2
..lol ... oui j'ai appuyé sur le bouton de menu, je l'ai aussi essayé avec et sans: fav.setShowAsAction (MenuItem.SHOW_AS_ACTION_ALWAYS);
misterbassman
Salut, peut - être que ce fil vous aidera ou consultez la démo de l' API pour un exemple de travail.
kameny

Réponses:

605

Appelez la super méthode:

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

Mettez des instructions log dans le code pour voir si la méthode n'est pas appelée ou si le menu n'est pas modifié par votre code.

Assurez -vous également que vous appelez setHasOptionsMenu(boolean)en onCreate(Bundle)notifier le fragment qu'il devrait participer à ses options de gestion du menu.

Kuffs
la source
2
Merci pour l'aide, j'ai ajouté la super méthode et j'ai réalisé que j'avais supprimé le @Override, j'ai donc ajouté ceci en arrière, eclipse a jeté une erreur, j'ai donc remplacé le MenuInflater pour importer android.view.MenuInflater; au lieu d'importer android.support.v4.view.MenuInflater; et maintenant tout fonctionne
misterbassman
183
ne pas appeler setHasOptionsMenu (true) dans onCreate du Fragment m'a eu deux fois maintenant
joshkendrick
7
Je transférais mon activité à un fragment et suis tombé sur ce problème. La signature de la méthode est passée de public booléen à public void et les arguments ont également changé. Assurez-vous d'en prendre note!
you786
14
Notez que Fragment.onCreateOptionsMenu (Menu, MenuInflater) est une méthode vide, donc appeler super n'est pas du tout nécessaire. La seule erreur ici était la mauvaise signature de la méthode et peut-être un setHasOptionsMenu () manquant dans onCreate ()
cmende
6
Remplacez super.onCreateOptionsMenu par inflater.inflate (R.menu.menu_custom, menu);
Code_Worm
197

J'ai eu le même problème, mais je pense qu'il vaut mieux résumer et introduire la dernière étape pour le faire fonctionner:

  1. Ajoutez la méthode setHasOptionsMenu (true) dans la méthode de votre fragment onCreate(Bundle savedInstanceState).

  2. Remplacez onCreateOptionsMenu(Menu menu, MenuInflater inflater)(si vous voulez faire quelque chose de différent dans le menu de votre fragment) et les onOptionsItemSelected(MenuItem item)méthodes de votre fragment.

  3. Dans onOptionsItemSelected(MenuItem item)la méthode de votre activité, assurez-vous de renvoyer false lorsque l'action de l'élément de menu sera implémentée dans onOptionsItemSelected(MenuItem item)la méthode de Fragment.

Un exemple:

Activité

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

Fragment

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;
}
Marco HC
la source
2
setHasOptionsMenu(true);
Chad Bingham
1
Sur un viewPager sur certains appareils, le menu n'est affiché que la deuxième fois que vous accédez au fragment
Roel
3
@Marco HC votre code fonctionne bien. Mais que se passe-t-il si je souhaite masquer une partie du menu Activité ou Fragment? Vous avez mentionné où implémenter quel menu d'options (En activité et fragment). Mais que faire si je veux cacher un menu?
Shreyash Mahajan
@iDroidExplorer conserve simplement une référence à ce MenuItem et définit la visibilité sur disparu ou invisible. C'est ça ta question?
Marco HC
@iDroidExplorer J'ai essayé son code et je ne sais pas comment mais il masque automatiquement le menu lorsque je passe à d'autres fragments.
Noor Ali Butt
156

Si vous trouvez que la onCreateOptionsMenu(Menu menu, MenuInflater inflater)méthode n'est pas appelée, assurez-vous d'appeler la onCreate(Bundle savedInstanceState)méthode suivante à partir du fragment :

setHasOptionsMenu(true)
Matthew Blackford
la source
Cela me donne une erreur comme NullPointerException
Pratik Butani
2
Bon point. J'appelais la méthode setHasOptionMenu à partir de la méthode statique newInstance. Comme je n'attachais mon fragment que lorsque saveInstanceState était nul, lorsque la configuration de l'écran avait changé, le menu ne serait pas créé. La méthode onCreate du fragment est le bon endroit où définir setHasOptionMenu sur true.
argenkiwi
1
J'utilise un Toolbaret j'ai dû appeler setHasOptionsMenu(true)à la onCreateView()place onCreate()pour le faire.
CLOUGH
60

Si vous avez besoin d'un menupour rafraîchir un webviewintérieur spécifiqueFragment , vous pouvez utiliser:

Fragment :

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>
CONvid19
la source
31

TL; DR

Utilisez le android.support.v7.widget.Toolbaret faites simplement:

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

Barre d'outils autonome

La plupart des solutions suggérées comme setHasOptionsMenu(true)ne fonctionnent que lorsque l' activité parent a la barre d'outils dans sa disposition et la déclare via setSupportActionBar(). Ensuite, les fragments peuvent participer à la population de menus de cette ActionBar exacte :

Fragment.onCreateOptionsMenu (): initialise le contenu du menu d'options standard de l'hôte Fragment.

Si vous voulez une barre d'outils et un menu autonomes pour un fragment spécifique vous pouvez effectuer les opérations suivantes:

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

Oui, c'est aussi simple que ça. Vous n'avez même pas besoin de remplacer onCreate()ouonCreateOptionsMenu() .

PS: Cela ne fonctionne qu'avec android.support.v4.app.Fragmentet android.support.v7.widget.Toolbar(assurez-vous également d'utiliser AppCompatActivityet un AppCompatthème dans votre styles.xml).

Marius
la source
1
m'a vraiment beaucoup aidé
brahmy adigopula
23

Dans le, menu.xmlvous devez ajouter tous les éléments du menu. Ensuite, vous pouvez masquer les éléments que vous ne souhaitez pas voir lors du chargement initial.

menu.xml

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

Ajoutez setHasOptionsMenu(true)la méthode onCreate () pour appeler les éléments de menu de votre classe Fragment.

FragmentClass.java

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

Vous n'avez plus besoin de redéfinir onCreateOptionsMenuvotre classe Fragment. Les éléments du menu peuvent être modifiés (ajouter / supprimer) en remplaçant la onPrepareOptionsMenuméthode disponible dans Fragment.

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

}
Parinda Rajapaksha
la source
16

Vous devez utiliser menu.clear () avant de gonfler les menus.

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

et

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }
Spl2nky
la source
1
Cela est correct lorsque vous souhaitez différents menus dans différents fragments et que vous ajoutez des fragments au lieu de les remplacer.
Akshay Mahajan
Je vous remercie! menu.clear () m'aide à supprimer l'option de menu Activité.
kimcy929
13

Dans mon cas, voici les étapes.

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

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

Étape 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);
}
Harry Zhang
la source
J'avais déjà un menu sur l'activité principale, en utilisant le menu.clear()menu précédent effacé. A travaillé pour moi :)
Anbuselvan Rocky
8

Si vous souhaitez ajouter votre menu personnalisé

@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);
}
Ezequiel García
la source
que se passe-t-il s'il y a un onglet et que vous souhaitez gonfler différents menus pour chaque fragment?
Jainam Jhaveri
7

J'ai eu le même problème, mes fragments étaient des pages d'un ViewPager. La raison pour laquelle cela se produisait était que j'utilisais le gestionnaire de fragments enfant plutôt que le gestionnaire de fragments de support d'activité lors de l'instanciation de FragmentPagerAdapter.

farid_z
la source
3

Fichier de menu:

<?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>

Code d'activité:

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

Code de fragment:

@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;
}
Suyog Gunjal
la source
3

Votre code va bien. Seul le super manquait dans la méthode:

@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);
}
AlexPad
la source
2

Je devenais fou parce qu'aucune des réponses ici ne fonctionnait pour moi.

Pour afficher le menu que j'ai dû appeler: setSupportActionBar(toolbar)

Terminé!

Remarque: si votre toolbarvue n'est pas dans la même disposition d'activité, vous ne pouvez pas utiliser l'appel ci-dessus directement à partir de votre classe d'activité, dans ce cas, vous devrez obtenir cette activité à partir de votre classe de fragments, puis appeler le setSupportActionBar(toolbar). Rappel: votre classe d'activité doit étendre AppCompatActivity.

J'espère que cette réponse vous aidera.

Filipe Brito
la source
1

La définition du menu d'options après la création de la vue fragmentaire a bien fonctionné pour moi.

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setHasOptionsMenu(true);        
}
Jerry Frost
la source
1

Mon problème était légèrement différent. J'ai tout bien fait. Mais j'héritais de la mauvaise classe pour l'activité hébergeant le fragment.

Donc, pour être clair, si vous remplacez onCreateOptionsMenu(Menu menu, MenuInflater inflater)le fragment, assurez-vous que votre classe d'activité qui héberge ce fragment hériteandroid.support.v7.app.ActionBarActivity (au cas où vous voudriez prendre en charge un niveau d'API inférieur à 11).

J'héritais de la prise android.support.v4.app.FragmentActivityen charge du niveau API inférieur à 11.

Krishna Deepak
la source
1

Je voudrais ajouter une chose à cela et la raison pour laquelle cela ne fonctionnait pas pour moi.

C'est similaire à la réponse de Napster.

  1. Assurez-vous que l'activité d'hébergement de votre fragment s'étend AppCompatActivity, non FragmentActivity!

    public class MainActivity extends AppCompatActivity {
    
    }

    Dans la documentation de référence Google pour FragmentActivity:

    Remarque: Si vous souhaitez implémenter une activité qui comprend une barre d'action, vous devez utiliser à la place la classe ActionBarActivity, qui est une sous-classe de celle-ci, vous permet donc d'utiliser des API de fragmentation au niveau 7 et supérieur de l'API.

  2. Pour mettre à jour la réponse de Napster - ActionBarActivitydésormais obsolète, utilisez AppCompatActivityplutôt.

  3. Lors de l'utilisation AppCompatActivity, assurez-vous également de définir "le thème d'activité Theme.AppCompatou un thème similaire" (Google Doc).

Remarque: android.support.v7.app.AppCompatActivityest une sous-classe de la android.support.v4.app.FragmentActivityclasse (voir le document de référence AppCompatActivity ).

Bastien
la source
1

Dans votre dossier de menu, créez un fichier xml .menu et ajoutez ce 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" />

Dans votre classe de fragment, remplacez cette méthode et

implement SearchView.OnQueryTextListener    in your fragment class



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

}

Maintenant, configurez simplement votre fichier xml de menu dans la classe de fragment

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

}
pavel
la source
0

Si tout ce qui précède ne fonctionne pas, vous devez déboguer et vous assurer que la fonction onCreateOptionsMenu a été appelée (en plaçant le débogage ou en écrivant le journal ...)

S'il n'est pas exécuté, votre thème Android ne prend peut-être pas en charge la barre d'action. Ouvrez AndroidManifest.xml et définissez la valeur pour android:themeavec la barre d'action de prise en charge du thème :

 <activity
     android:name=".MainActivity"
     android:label="@string/app_name"
     android:theme="@style/Theme.AppCompat">
Loup gris
la source
0

sur votre méthode onCreate , ajoutez setHasOptionMenu ()

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

Ensuite , passer outre votre 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);
}
Ashana.Jackol
la source