juil
19
2010

[Tutoriel Android] Partie 4 – Au menu de ce soir

Qu’avons-nous au menu de ce soir ?

Bonjour et bienvenue dans la 4ème partie du tutoriel Android, nous allons aborder aujourd’hui le sujet sulfureux des menus !

Une bonne application mérite son menu de toute évidence et il est fort à parier qu’un jour vous ayez besoin d’en rajouter un dans votre application.

Commençons tout d’abord par lister les types de menus existants au sein de notre plateforme :

Les menus d’options : Nous les retrouvons quand nous cliquons sur le bouton “Menu” de notre téléphone, ils s’affichent en bas de l’écran.

Menu d'options

Les menus d’options à préférences étendues : Ils permettent d’afficher un menu en bas de l’écran lors de l’appui sur une touche d’option d’un menu.

Menu expand

Les menus contextuels : On les retrouve généralement en cliquant sur un objet avec un appui long ou court, une fenêtre de choix s’affiche alors.

Menu contextuel

Voilà nous avons fait le tour des menus disponibles, on a largement de quoi faire n’est-ce pas ?

Création de notre premier menu d’options

Nous allons créer notre premier menu d’options, pour cela créez un tout nouveau projet.

Ouvrez le fichier contenant l’activité principale du projet “MonActitive.java”

Nous allons ajouter un Override à la méthode onCreateOptionsMenu(Menu menu)

Puis nous allons ajouter le code suivant :

@Override

public boolean onCreateOptionsMenu(Menu menu) {

menu.add("Options");

menu.add("Quitter");

return true;

}

Lancez l’application et cliquez sur le bouton “Menu”, tadam !

Mon premier menu

Le menu s’ouvre et nos deux options sont à l’intérieur. Je ne vais pas expliquer plus loin comment faire un menu manuellement, car ce n’est pas facile à maintenir au niveau code.

Nous allons utiliser une autre méthode de type XML, qui sera plus facile à gérer durant les phases de développement d’une application mobile.

Créez un nouveau fichier XML à l’aide de l’outils ADT comme suit :

Création XML

Nous allons rajouter dans le fichier XML les différents menus, ce qui nous donnera quelque chose de similaire à ceci :

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

<menu

xmlns:android="http://schemas.android.com/apk/res/android">

<item android:title="Options" android:id="@+id/itemOptions"></item>

<item android:title="Quitter" android:id="@+id/itemQuitter"></item>

</menu>

Puis dans le code de la méthode onCreateOptionsMenu, nous allons récupérer notre menu sous forme XML et l’afficher.

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Création du menu inflater

MenuInflater inflater = getMenuInflater();

// On envoi a la variable menu le fichier xml parsé par l'inflater

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

return true;

}

Voilà, relançons l’application et nous nous retrouvons avec exactement le même menu que tout à l’heure à l’exception que celui-ci est en format XML, donc plus facilement éditable lors du développement.

Nous allons rajouter des événements lorsque l’on clique sur un des items du menu, grâce à la méthode onMenuItemSelected(int featureId, MenuItem item) que nous allons Override.

Les paramètres sont :

featureId : L’id du panel contenant le menu

Item : L’item qui est cliqué

L’objet item contient une méthode getItemId qui nous renvoie un entier que l’on compara au Id des items du fichier XML.

Le code :

@Override

public boolean onMenuItemSelected(int featureId, MenuItem item) {

// On récupère l'id de l'item et on le compare

switch (item.getItemId()) {

// S'il est égal à itemOptions

case R.id.itemOptions:

// On affiche un message

Toast.makeText(this, "Ouverture des options", Toast.LENGTH_SHORT).show();

return true;

// S'il est égal à itemQuitter

case R.id.itemQuitter:

// On ferme l'activité

finish();

return true;

}

return super.onMenuItemSelected(featureId, item);

}

Lancez à nouveau notre exemple et regardez le résultat ;)

Nous pouvons également créer des groupes de menus avec des items à l’intérieur pour plus de lisibilité : ajouter une icône à chaque menu etc…

La documentation android est disponible ici pour pour d’explication http://developer.android.com/guide/topics/ui/menus.html

Création d’un menu contextuel

Nous allons rajouter à notre application le pouvoir (de la force jeune jedi) d’ouvrir un menu contextuel.

Tout cela grâce à onCreateContextMenu(ContextMenu menu, View v,  ContextMenuInfo menuInfo) que nous allons également Override dans notre activité.

Créons une fois de plus un menu au format XML comme à l’étape précédente, je l’ai nommé “monmenucontextuel.xml” avec pour code :

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

<menu

xmlns:android="http://schemas.android.com/apk/res/android">

<item android:id="@+id/itemCoucou" android:title="Coucou"></item>

<item android:id="@+id/itemHello" android:title="Hello"></item>

</menu>

Puis dans le layout nommé main.xml je rajoute un identifiant au textview déjà existant.

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<TextView

android:id="@+id/monTextView"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/hello"

/>

</LinearLayout>

Et dans notre action onCreateOptionsMenu de notre activité, nous enregistrons le fait que lorsque l’on clique sur ce textview nous ouvrirons un menu contextuel.

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

registerForContextMenu((TextView)findViewById(R.id.monTextView));

}

Dans la méthode onCreateContextMenu, nous allons faire un inflate sur le menu contenu sous forme XML.

@Override

public void onCreateContextMenu(ContextMenu menu, View v,

ContextMenuInfo menuInfo) {

super.onCreateContextMenu(menu, v, menuInfo);

MenuInflater inflater = getMenuInflater();

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

}

Lancez l’application et voyez par vous-même que le menu s’ouvre lorsque l’on maintient le clique sur le textview. Maintenant, il ne reste plus qu’à vérifier les items cliqués du menu.

De même que pour le menu des options, une méthode existe pour vérifier cela, elle se nomme onContextItemSelected avec en paramètre l’item sélectionné.

Vérifions comme précédemment l’item qui est sélectionné à l’aide d’un switch et affichons quelque chose :

@Override

public boolean onContextItemSelected(MenuItem item) {

// On récupère l'id de l'item et on le compare

switch (item.getItemId()) {

// S'il est égal à itemCoucou

case R.id.itemCoucou:

// On affiche un message

Toast.makeText(this, "Coucou tout le monde !", Toast.LENGTH_SHORT).show();

return true;

// S'il est égal à itemHello

case R.id.itemHello:

// On affiche un message

Toast.makeText(this, "Hello World !", Toast.LENGTH_SHORT).show();

return true;

}

return super.onContextItemSelected(item);

}

A l’affichage cela nous donne :

Mon premier menu contextuel

Et si l’on choisit l’item “Coucou” :

Ca fonctionne

Et voilà, vous savez désormais faire des menus d’options et des menus contextuels.

A la prochaine ;)

  • http://SiteWeb damien

    Salut
    Un tuto intéressent.
    J’aimerais bien savoir s’il n’est pas possible de lancer un menu ou menu contextuel à partir d’une view ou d’un bouton, mais sans devoir maintenir le doigt appuyé dessus. :wassat:

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Si c’est possible, on utilise le listener de la pression du doigt pour l’afficher, suffit d’utiliser le même code mais pour le listener du clic sur le bouton ;)

  • http://SiteWeb Gg

    Merci pour ce tuto !

    J’ai constaté que si la méthode onMenuItemSelected est présente alors la méthode onContextItemSelected ne sera pas lue, il faut donc placer tous les CASE dans un SWITCH global comprenant à la fois le traitement du menu contextuel et des menus d’options.

  • http://SiteWeb hugo

    Super tuto mais je comprend pas comment ne pas maintenir le boutton

  • http://SiteWeb hugo

    C’est bon j’ai trouver merci
    P.S pour ce qui ne trouve pas :
    public void onClick(View v) {
    registerForContextMenu(v);
    openContextMenu(v);
    }

  • http://SiteWeb Toneo

    Slt
    Un grand merci pour ce tuto
    seulement voila, je me demandais s’il yavai un moyen qu’en cliquant sur un élement du menu, ce dernier nous renvois un edittext et que apres en on soit capable de recupérer le texte saisi.
    Merci

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Bonjour Toneo,

    Tu as plusieurs solutions, soit un DialogBox, soit une autre Activity.

    Voilà j’espère t’avoir éclairé ;)

  • http://SiteWeb Amina

    Salut,
    Merci pour ce tuto il est super utile !
    Cependant, je travaille avec la version Android 2.3 et dans les fichiers xml je veux ajouter les champs android:icon pour pouvoir afficher des icones dans mon menu mais ça marche pas :sad: ..

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Contact moi par mail, je pourrais t’aider en fin de journée (travail oblige).

    Merci

  • http://SiteWeb steph

    Bonjour,
    d’abord merci pour ces tutoriels.

    Ensuite je voudrais poser quelques questions au sujet des menus :

    1. Dans ton exemple on voit que le menu contextuel a un titre (sur fond noir).
    j’ai trouvé la méthode setHeaderTitle() pour le mettre. Mais existe -t-il un moyen via le fichier xml ? car je n’ai rien trouvé par là.

    2. D’après la manière de créer un menu contextuel, j’ai l’impression qu’on ne peut avoir qu’un seul menu par activité. Est-ce le cas ?
    On ne peut avoir de menu différent suivant les view à l’écran ?
    La méthode registerForContextMenu ne permet pas d’indiquer quel menu à afficher.

    Enfin Quid des “menus d’options à préférences étendues” ?

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Bonjour Steph,

    1) C’est pas la propriété android:title dans le XML par hasard ?

    2) Si mais il faut vérifier la vue avant de créér le menu

    3) Le registerForContextMenu permet de dire a Android que l’on bind un menu sur l’objet de l’interface, après tout se passe dans le onCreateContextMenu, à ce moment la il faut vérifier la vue sélectionnée.

    Les menus d’options à préférences étendues, je n’en ai jamais fait et très peux de gens l’utilise, mais il est vrai que j’aurais pu m’y pencher.

    Cdt.

  • http://SiteWeb steph

    Pour ma première question j’y arrive pas mais c’est pas grave j’utiliserai la méthode.

    Pour le reste j’ai compris, merci.

  • http://SiteWeb biboune

    Bonjour,

    Voilà je développe une application android et je rencontre un problème :
    j’ai un menu contextuel qui s’ouvre mais lorsque je choisis une option, rien ne se passe.
    Voici le code :

    // Menu contextuel : long “clic” sur un compte
    public void onCreateContextMenu(ContextMenu menu, View v,
    ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    menu.add(0, 0, 0, “Blabla”);
    menu.add(0, 1, 0, “Lorem”);
    menu.add(0, 2, 0, “Ipsum”);
    menu.add(0, 3, 0, “Test”);
    }

    // Action réalisée au clic sur une option du menu contextuel
    @Override
    public boolean onContextItemSelected(MenuItem aItem) {
    Log.d(“menucontextuel”, “ca marche!!”);
    AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) aItem.getMenuInfo();
    float position = menuInfo.position;
    switch (aItem.getItemId()) {
    case 0:
    Log.d(“voir”, “ok”);
    return true;
    case 1:
    Log.d(“ouvrir”, “ok”);
    return true;
    case 2:

    Log.d(“remonter1″, “ok”);
    return true;
    case 3: // Remonter tous les comptes

    Log.d(“remonter2″, “ok”);
    return true;
    }
    return false;
    }

    En regardant dans le logcat, je ne vois aucun des message qui sont sensés s’afficher…
    Need help please… Merci d’avance

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    N’aurais tu pas par hasard un onMenuItemSelected qui traine dans ton activity ?

  • http://SiteWeb biboune

    Tu es devin? :o
    Oui en effet, merci =)
    Mais, ne serait-ce pas possible d’avoir un menu “normal” et un menu contextuel dans la même activité?

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier
  • http://SiteWeb Florian

    Salut,
    J’ai un problème avec “R”….
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    // Création du menu inflater
    MenuInflater inflater = getMenuInflater();
    // On envoi a la variable menu le fichier xml parsé par l’inflater
    inflater.inflate(R.monmenu.menu, menu);
    return true;
    }

    Il me dit de créer un champs ou une constante dans le type R :(
    Merci

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Un problème dans tes imports

    Vérifie les

  • http://SiteWeb Arnaud

    Super tuto ! J’ai déjà des idées plein la tête !

    Bravo !

  • Hataka

    Peux tu s’il te plait expliquer le but de @Override ?

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    @Override est une annotation qui va dire à ton compilateur que tu surcharges (réécrit sa version mère)

  • Hataka

    Merci !

  • Chris

    Je voudrais créer un menu contextuel qui s’ouvre quand on clique sur les élement d’une listview. Pourrais-tu expliciter un peu plus en détail ce qu’il faudrait faire dans le onCreateContextMenu pour que le menu change en fonction de l’endroit de la listview où l’on a cliqué? Merci!

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    Bonjour Chris,

    Modifie cette partie
    registerForContextMenu((TextView)findViewById(R.id.monTextView));
    En remplaçant le TextView par ta listview

    Après tu récupères l’élément courant de la liste et le tour est joué ;)

  • Chris

    Merci, en fait je comprends pas comment récupérer ma position dans la liste. Voici mon code:

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,

    ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    int position=lvListe.getSelectedItemPosition();
    menu.add(0,1,0,”Coucou”);
    menu.add(0,2,1,String.valueOf(position));
    }

    Et le String.valueOf(position) me retourne -1 où que je clique :sad: .

    Ma liste est créee par ce code:
    lvListe = (ListView)findViewById(R.id.lvListe);
    registerForContextMenu((ListView)findViewById(R.id.lvListe));
    maBibliotheque=getServerData(strURL”);
    adapter = new JSONObjectAdapter(this, maBibliotheque);
    lvListe.setAdapter(adapter);

  • http://www.ace-art.fr/wordpress/ Pierre-Emmanuel Mercier

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
    ContextMenuInfo menuInfo) {
    // Création de ton menu
    getMenuInflater().inflate(R.menu.menu_server, menu);
    // La méthode parente (à faire en dernier)
    super.onCreateContextMenu(menu, v, menuInfo);
    }

    Ensuite ton menu s’ouvre.

    Et voici la dernière méthode pour faire fonctionner ton menu

    @Override
    public boolean onContextItemSelected(MenuItem item) {
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
    switch (item.getItemId()) {
    case R.id.monItem:
    break;
    }
    return super.onContextItemSelected(item);
    }

    Bonne chance à toi

  • Chris

    Ok merci beaucoup :smile: , j’ai rajouté la ligne:

    int position=info.position;

    Et j’ai exactement ce que je voulais obtenir. :smile:

  • Monfront A

    bonjour voila j’ai une question sur les menu contextuel!
    j’aimerai afficher le menu seulement par le code. je développe:

    j’ai un bout de code appelé par un bouton mais je voudrai afficher le menu seulement si tout c’est bien dérouler. 

    Or dans ton exemple le menu est afficher directement sur l’événement du bouton.

    Es ce que c’est compréhensible? merci d’avance

    et merci pour tes tutos vraiment bien fait et agréable ;)

  • http://www.ace-art.fr/wordpress Acesyde

    Bonjour,

    La solution la plus simple est de mettre un flag avant et de faire un return false si la condition ne correspond pas, pour ne pas afficher le menu dans le onCreateContextMenu.

  • 90s Adventure

    Hello
    ayant plusieurs activités qui s’enchaînentdans mon appli, comment faire pour éviter de répéter le code de gestion du menu contextuel dans chacune d’entre elles ?
    merci d’avance

  • http://www.ace-art.fr/wordpress Acesyde

    Il n’y a pas de miracle, sauf si tu mutualises le contenue dans des classes externes, mais c’est pas non plus top top