web-dev-qa-db-fra.com

Le fragment ne reçoit pas de rappels de menu

J'ai une classe de fragment qui étend Fragment et appelle setHasOptionsMenu pour participer au menu. Cette classe implémente également onCreateOptionsMenu, onPrepareOptionsMenu et onOptionsItemSelected.

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

Je charge dynamiquement ce fragment en utilisant un FragmentTransaction dans mon activité (qui étend FragmentActivity).

Cependant, aucun des rappels de menu (onCreateOptionsMenu, onPrepareOptionsMenu et onOptionsItemSelected) n'est appelé (j'ai débogué avec certains points d'arrêt dans ces méthodes) et le menu n'est pas affiché .

Suis-je en train de manquer quelque chose? Dois-je ajouter quelque chose dans mon activité?

J'utilise la bibliothèque de compatibilité Android, compilant avec le SDK L11 et testant dans un Xoom.

MODIFIER : J'ai trouvé le problème. Mon AndroidManifest cible le L11, cela semble masquer le bouton de menu et empêcher les rappels d'être appelés. Cependant, si je le supprime du manifeste, je perds certaines autres fonctionnalités dont j'ai besoin (par exemple l'état activé dans les listes). Quelqu'un sait-il comment résoudre ce problème (activez le bouton de menu) sans supprimer le targetSdkVersion=11 du Manifeste?

40
aromero

J'ai trouvé le problème. L'AndroidManifest cible le SDK 11, cela semble masquer le bouton de menu et empêcher les rappels d'être appelés. Je suppose que cela rompt la compatibilité du bouton de menu qui semble être remplacé par la barre d'action dans Android 3.0

2
aromero

Aromero, n'oubliez pas de remplacer le menu onCreateOptionsMenu en utilisant la version fragmentée de la méthode, similaire à ceci:

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

Soit dit en passant, cela va dans le fragment et s'ajoute au menu gonflé de l'activité, s'il y en a un. J'ai eu le même problème jusqu'à ce que je comprenne cela.

Kim

29
user553456

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 onCreate(Bundle savedInstanceState) de votre fragment.

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

  3. À l'intérieur de la méthode de votre activité onOptionsItemSelected(MenuItem item), assurez-vous de renvoyer false lorsque l'action d'élément de menu sera implémentée dans la méthode de onOptionsItemSelected(MenuItem item) 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) {
    // 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;
}

J'espère que cela vous sera utile.

À votre santé.

9
Marco HC

Si vous rencontrez ce problème avec ActionBarSherlock, vous devez vous assurer que vos fragments sont des SherlockFragments, pas de simples SupportFragments, et que ce que vous remplacez est

public void onPrepareOptionsMenu (com.actionbarsherlock.view.Menu menu) {

NE PAS

public void onPrepareOptionsMenu (Android.view.Menu menu) {

Si vous faites ce dernier, vous devriez obtenir une sorte d'avertissement indiquant que la fonction est définitive et que vous ne pouvez pas la remplacer. Ceci est un avertissement que vous essayez de remplacer la mauvaise fonction!

Si vous corrigez l'erreur en changeant la classe de SherlockFragment en un simple fragment, vous pouvez créer la fonction. . . mais il ne sera pas appelé.

9
Catherine Darrow

Si vous avez une activité et un fragment qui chargent chacun des éléments de menu, vous devez faire particulièrement attention aux substitutions que vous utilisez.

Les activités peuvent remplacer onOptionsItemSelected et onMenuItemSelected, mais les fragments ne peuvent remplacer que onOptionsItemSelected.

Si vous remplacez onMenuItemSelected dans votre activité et onOptionsItemSelected dans votre fragment, votre remplacement de fragment ne sera jamais déclenché.

À la place, utilisez onOptionsItemSelected dans l'activité et le fragment.

6
Error 454

Vous devez vous assurer d'appeler setHasOptionsMenu(true);onCreate ou onCreateView est appelé dans votre fragment.

Vous devez également implémenter la substitution de onCreateOptionsMenu à l'intérieur de votre fragment.

5
Nelson Ramirez

Un autre cas possible est lorsque vous utilisez un identifiant commun pour une action commune dans chaque fragment; par exemple R.id.action_add

Aujourd'hui, j'ai eu une telle situation: frapper le menu d'options [ajouter] a été invoqué le "mauvais" onOptionItemSelected parce que chaque fragment (remplacé dynamiquement en utilisant un DrawerLayout) avait le même R.id.action_add.

Petite histoire, si vous avez une telle situation vérifiez toujours que votre fragment est visible:

if (!isVisible()) return false;

Longue histoire, faites attention à la chaîne onOptionItemSelected!

  MainActivity
       |
       |  onOptionItemSelected
       +-----------------------
       |     return false
       |
 MyCoolFragment1
       |
       |  onOptionItemSelected
       +-----------------------
       |     return false
       |
 MyCoolFragment2
       |
       |  onOptionItemSelected
       +-----------------------
       |     return true
       |
[item selection handled]

Si vous ajoutez vos fragments avec (quelque chose comme) ceci:

getSupportFragmentManager()
   .beginTransaction()
   .replace(R.id.content_frame, MyCoolFragment1.newInstance())
   .commit() 

et vous avez défini le même identifiant pour une action commune (disons R.id.action_add) dans chaque fragment; n'oubliez pas d'ajouter cette ligne à chacun: if (! isVisible ()) return false;

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (!isVisible()) return false; // <-- Not visible? skip!

    if (item.getItemId() == R.id.action_add) {
        //.TODO whatever
        return true;  //.Handled!
    }

    return false; //.Skip
}
4
Luca Sepe

J'ai eu ce problème lorsque j'utilisais ViewPagerIndicator conjointement avec ActionBarSherlock. Bien qu'il semble que ce soit fixe j'ai quand même rencontré le problème. Le travail que j'ai trouvé consistait à appeler manuellement le fragment.

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
    Toast.makeText(this, "From activity", Toast.LENGTH_SHORT).show(); // TODO
    Fragment currentFragment = mAdapter.getItem(mPager.getCurrentItem());
    if (currentFragment != null && currentFragment instanceof SherlockFragment)
    {
        ((SherlockFragment)currentFragment).onOptionsItemSelected(item);
    }
    return super.onOptionsItemSelected(item);

}
3
AlexUT

Si votre barre d'outils est définie dans le XML d'activité parent, assurez-vous de le faire dans votre fragment

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    ....
    Toolbar toolbar = (Toolbar)getActivity().findViewById(R.id.toolbar);
    ((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
    setHasOptionsMenu(true);
}

Et puis bien sûr, remplacez onCreateOptionsMenu comme ci-dessous

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

C'est la seule solution qui a fonctionné pour moi!

1
reavcn

Depuis le Android - lien

Remarque: Si vous gonflez des éléments de menu à partir d'un fragment, via le rappel onCreateOptionsMenu () de la classe Fragment, le système appelle onOptionsItemSelected () pour ce fragment lorsque l'utilisateur sélectionne l'un de ces éléments. Cependant, l'activité a la possibilité de gérer l'événement en premier, donc le système appelle d'abord onOptionsItemSelected () sur l'activité, avant d'appeler le même rappel pour le fragment = . Pour vous assurer que tous les fragments de l'activité ont également la possibilité de gérer le rappel, passez toujours l'appel à la superclasse comme comportement par défaut au lieu de retourner false lorsque vous ne gérez pas l'élément.

Par conséquent Marco HC est la meilleure réponse de toutes.

1
ik024

Je pense que vous avez implémenté onCreateOptionsMenu, onPrepareOptionsMenu et onOptionsItemSelected dans la classe que extends Fragment. Essayez de le faire dans votre classe d'activité où vous chargez ce fragment

1

J'ai eu le même problème et la solution qui a fonctionné pour moi est:

  1. Supprimez ou commentez tout onOptionsItemSelected (), onMenuItemSelected () même onPrepareOptionMenu () et laissez dans Activity onCreateOptionsMenu () uniquement:

    @Override
    public boolean onCreateOptionsMenu(Menu menu){
    MenuInflater inflater=getMenuInflater();
    inflater.inflate(R.layout.menu, menu);
    return true;
    }
    
  2. Dans la classe Fragment, dans onCreateView (), mettez:

    setHasOptionsMenu(true);
    
  3. Dans la classe Fragment, ajoutez:

    @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
     super.onCreateOptionsMenu(menu,inflater);      
     }
    
    @Override
     public boolean onOptionsItemSelected(MenuItem item){           
             switch(item.getItemId()){
             case R.id.action_insert:
                //doing stuff
             return true;
             }
             return false;
         }
    

Testé et travaillé sur Android 4.4

1
Augusto Picciani