67 votes

Comment gérer onContextItemSelected dans une activité multi-fragments

Je suis en train d'essayer d'adapter mon application pour utiliser les "Bibliothèques de Compatibilité pour Android v4" pour fournir les avantages de l'utilisation de fragments de même pour Android 1.6 utilisateurs.

Jusqu'à présent cela a été possible sans gros problèmes, mais la mise en œuvre d'un menu contextuel semble être plus délicat...

  • L'activité principale de l'application est l'extension de la FragmentActivity classe.
  • Les fragments sont tous basés sur un classe qui étend le Fragment de la classe.
  • Le fragment de la classe est l'appel de registerForContextMenu() dans son onCreateView() la méthode et redéfinit les méthodes onCreateContextMenu() et onContextItemSelected().

Pour onCreateContextMenu() cela fonctionne assez bien. Le menu contextuel est gonflé à partir d'un fichier de ressources et légèrement modifiés en fonction de l'élément sélectionné (qui est basé sur une liste... même si le fragment n'est pas un ListFragment).

Le problème se produit lorsqu'un contexte d'entrée de menu est sélectionné. onContextItemSelected() est appelée pour tous les existants actuellement fragments en commençant par le premier ajoutée.

Dans mon cas, les fragments sont utilisées pour afficher le contenu d'une structure de dossier. Lorsque le menu contextuel d'un sous-dossier fragment est ouvert et un élément de menu est sélectionné, onContextItemSelected() est appelée en premier sur les niveaux supérieurs (en fonction du nombre de fragments sont autorisés/visible en ce moment).

Maintenant, j'utilise une solution de contournement par un champ sur le niveau d'activité qui détient le tag de dernier fragment d'appeler ses onCreateContextMenu(). De cette façon, je peux appeler "return super.onContextItemSelected(objet)" dans le début de onContextItemSelected() lorsque la balise n'est pas le même que getTag(). Mais cette approche semble un peu sale pour moi.

Pourquoi est-onContextItemSelected() a appelé tous les fragments? et pas juste celui qui a été l'appel de onCreateContextMenu()? Quelle est la plus élégante pourquoi gérer cela?

Merci à l'avance.

67voto

Waterbear Points 918

Je vais poster une réponse, même si vous avez trouvé une solution de contournement parce que je viens de traiter un problème similaire. Lorsque vous gonflez le menu contextuel d'un fragment spécifique, d'attribuer à chaque élément de menu un groupId qui est unique pour le fragment. Tester le groupId dans 'onContextItemSelected.' Par Exemple:

public void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {
    menu.add(UNIQUE_FRAGMENT_GROUP_ID, MENU_OPTION_1, 0, R.string.src1);
    menu.add(UNIQUE_FRAGMENT_GROUP_ID, MENU_OPTION_2, 0, R.string.src2);
}
public boolean onContextItemSelected(MenuItem item) {
    //only this fragment's context menus have group ID of -1
    if (item.getGroupId() == UNIQUE_FRAGMENT_GROUP_ID) {
        switch(item.getItemId()) {
        case MENU_OPTION_1: doSomething(); break;
        case MENU_OPTION_2: doSomethingElse(); break;
    }
}

De cette façon, tous vos fragments de toujours recevoir des appels à "onContextItemSelected", mais seulement de la bonne volonté de répondre, évitant ainsi la nécessité de l'activité d'écriture au niveau du code. Je suppose que d'une version modifiée de cette technique pourrait fonctionner même si vous n'utilisez pas le menu.ajouter(...)'

54voto

Sergey Glotov Points 8390

Une autre solution:

 @Override
public boolean onContextItemSelected(MenuItem item) {
    if (getUserVisibleHint()) {
        // context menu logic
        return true;
    }
    return false;
}
 

Basé sur ce patch de Jake Wharton.

8voto

azelez Points 1081

J'ai aimé la solution simple de Sergei G (basée sur le correctif de Jake Wharton), mais inversée car il est plus facile d'ajouter à plusieurs fragments:

 public boolean onContextItemSelected(android.view.MenuItem item) 
{  
    if( getUserVisibleHint() == false ) 
    {
        return false;
    }

    // The rest of your onConextItemSelect code
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
 }
 

Après cela, le code est le même qu'avant.

4voto

Rawpal Points 11

J'ai découvert une solution très facile. Comme onCreateContextMenu () est appelé à chaque fois que le ContextMenu est créé, je définis une variable booléenne sur true.

 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    MenuInflater inflater = getActivity().getMenuInflater();
    inflater.inflate(R.menu.film_menu, menu);
    bMenu=true;
}
 

La seule autre chose à faire est de demander la variable OnContextItemSelected ().

 public boolean onContextItemSelected(MenuItem item) {
    if (bMenu) {
        bMenu=false;
        if (item.getItemId() == R.id.filmProperties) {
            ///Your code
            return true;
        } else {
            return super.onContextItemSelected(item);
        }
    } else {
        return super.onContextItemSelected(item);
    }
}
 

C'est tout.

2voto

Lars K. Points 624

J'ai trouvé une alternative. Cela ne change rien à mon problème ci-dessus, mais il le rend inutile.

J'ai supprimer le menu contextuel complètement de ma demande. Au lieu de cela j'ai fait une capture de la longclick sur un élément de liste et de modifier le visible boutons de la barre d'action en ce moment. Du point de vue utilisateur, c'est beaucoup plus de la tablette comme un menu contextuel.

En arrière des applications compatibles avec l'actionbar n'existe pas. Donc j'ai décidé de construire mon propre (sorte de barre d'outils en haut) pour les appareils d'avant en Nid d'abeille.

Si vous souhaitez rester avec le menu contextuel, je n'ai pas trouvé une meilleure solution que la solution de contournement que j'ai mentionné ci-dessus.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by: