74 votes

Gestion du titre de la barre d'action avec la pile arrière du fragment ?

J'ai un Activity où je charge dans un ListFragment et, en cliquant, on descend d'un niveau et on obtient un nouveau type d'informations. ListFragment est affichée, remplaçant celle d'origine (en utilisant l'option showFragment méthode ci-dessous). Celle-ci est placée sur la pile arrière.

Au début, l'activité affiche le titre par défaut dans la barre d'action (c'est-à-dire qu'il est défini automatiquement sur la base de l'application android:label ).

Lors de l'affichage de la liste du niveau suivant de la hiérarchie, le nom de l'élément sur lequel on a cliqué doit devenir le titre de la barre d'action.

Cependant, en appuyant sur Back J'aimerais que le titre original par défaut soit restauré. Ce n'est pas quelque chose FragmentTransaction connaît, donc le titre n'est pas rétabli.

J'ai vaguement lu quelque chose sur FragmentBreadCrumbs mais cela semble nécessiter l'utilisation d'une vue personnalisée. J'utilise ActionBarSherlock et je préférerais ne pas avoir ma propre vue de titre personnalisée.

Quelle est la meilleure façon de procéder ? Est-il possible de le faire sans avoir recours à un tas de code passe-partout et sans devoir garder la trace des titres affichés en cours de route ?


protected void showFragment(Fragment f) {
  FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
  ft.replace(R.id.fragment_container, f);
  ft.addToBackStack(null);
  ft.commit();
}

124voto

Warpzit Points 11150

Dans chaque fragment et chaque activité, je change le titre comme ceci. De cette façon, le titre actif sera toujours correct :

@Override
public void onResume() {
    super.onResume();
    // Set title
    getActivity().getActionBar()
        .setTitle(R.string.thetitle);
}

Il y a des cas où onResume n'est pas appelé à l'intérieur des fragments. Dans certains de ces cas, nous pouvons utiliser :

public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if(isVisibleToUser) {
        // Set title
        getActivity().getActionBar()
            .setTitle(R.string.thetitle);
    }
}

2 votes

Je n'ai pas eu besoin de faire un casting, ou d'obtenir la barre d'action (c'est à dire que j'ai juste appelé getActivity().setTitle(...) ), mais c'est une approche raisonnable. Merci.

9 votes

-1. Cette approche est incorrecte ! Selon les directives de conception d'Android, lors du changement de fragments à l'aide du tiroir de navigation, le titre de la barre d'action ne doit changer que dans le rappel onClosed du tiroir de navigation. Votre approche modifiera de manière incorrecte le titre avant la fermeture du tiroir de navigation.

6 votes

@zyamys Si vous avez une meilleure suggestion, je serai heureux de l'upvoter. C'était la meilleure réponse que j'ai pu trouver à ce moment-là.

28voto

Maciej Pigulski Points 914

Comme la réponse originale est assez ancienne, cela pourrait également vous aider. Comme l'indique la documentation, il est possible d'enregistrer un fichier listener pour écouter sur la pile arrière les changements dans l'hébergement Activity :

getSupportFragmentManager().addOnBackStackChangedListener(
        new FragmentManager.OnBackStackChangedListener() {
            public void onBackStackChanged() {
                // Update your UI here.
            }
        });

Ensuite, identifiez la situation dans la méthode de rappel et définissez un titre approprié, sans accéder à l'élément ActionBar de la Fragment .

C'est une solution plus élégante car le Fragment n'a pas à connaître le ActionBar existence et Activity est généralement l'endroit qui gère le backstack, il semble donc plus approprié de le gérer à cet endroit. Fragment doit à tout moment être considérée uniquement par son propre contenu, et non par son environnement.

Plus d'informations sur le sujet dans le documentation .

1 votes

L'autre réponse est ancienne, mais je trouve toujours que c'est la façon la plus simple et la plus pragmatique de s'assurer que le titre est toujours correct. Comme mentionné dans mon commentaire, vous n'avez pas besoin d'accéder directement à la barre d'action. La solution proposée ici nécessite plus de code, mais n'est pas non plus utile pour votre fragment initial, qui n'est normalement pas ajouté à la pile arrière.

1 votes

De même, il n'y a rien de mal à accéder à la barre d'action à partir de fragments. Google fournit également une API pour modifier les éléments de menu à l'intérieur des fragments.

2 votes

Après un certain temps, je suis arrivé à la conclusion que les deux solutions sont bonnes, cela dépend juste de votre cas d'utilisation, parfois il sera plus pratique d'utiliser onResume et parfois un gestionnaire de fragment listener. Donc, dans l'ensemble, il est bon de connaître ses outils, de sorte que vous puissiez les appliquer de manière adéquate à vos besoins.

11voto

Meanman Points 171

Laissez l'activité de contrôle faire tout le travail comme suit :

Écouter les événements de la pile arrière (dans onCreate() de l'activité) :

// Change the title back when the fragment is changed
    getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            Fragment fragment = getFragment();
            setTitleFromFragment(fragment);
        }
    });

Obtenez le fragment actuel du conteneur :

/**
 * Returns the currently displayed fragment.
 * @return
 *      Fragment or null.
 */
private Fragment getFragment() {
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.container);
    return fragment;
}

Définissez le fragment à l'intérieur de la vue du contenu :

private void setFragment(Fragment fragment, boolean addToBackStack) {
    // Set the activity title
    setTitleFromFragment(fragment);
    .
    .
    .
}

0 votes

Il ne s'agit pas de "laisser l'activité faire tout le travail" si vous devez implémenter une interface dans chacun des éléments suivants Fragment de sorte que setTitleFromFragment() peut retrouver son titre. Rien de tout cela ne semble correspondre à la partie "sans un tas de code passe-partout" de ma question.

0 votes

Il n'y a aucune mention d'une interface dans ma solution, votre activité peut vérifier l'instance du fragment et définir le titre en fonction de cela, laissant ainsi votre activité faire tout le travail. Toutes ces méthodes sont définies à l'intérieur de l'activité.

0 votes

Oui, cela semble probablement encore pire du point de vue de la conception/séparation des préoccupations/réutilisabilité. De plus, cela change deux fois le titre de manière redondante pour chaque fragment ajouté à la pile arrière, puisque la méthode setTitleFromFragment est appelée inconditionnellement dans setFragment, je suppose ? Quoi qu'il en soit, merci, mais je vais m'en tenir à la réponse pragmatique et simple acceptée :)

7voto

Lee Hounshell Points 542

Il est préférable de laisser l'OS faire le plus gros du travail possible. En supposant que chaque fragment est correctement nommé en utilisant .addToBackStack("title") alors vous pouvez remplacer onBackPressed par quelque chose comme ceci pour obtenir le comportement souhaité :

// this example uses the AppCompat support library
// and works for dynamic fragment titles
@Override
public void onBackPressed() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    int count = fragmentManager.getBackStackEntryCount();
    if (count <= 1) {
        finish();
    }
    else {
        String title = fragmentManager.getBackStackEntryAt(count-2).getName();
        if (count == 2) {
            // here I am using a NavigationDrawer and open it when transitioning to the initial fragment
            // a second back-press will result in finish() being called above.
            mDrawerLayout.openDrawer(mNavigationDrawerFragment.getView());
        }
        super.onBackPressed();
        Log.v(TAG, "onBackPressed - title="+title);
        getSupportActionBar().setTitle(title);
    }
}

7voto

JCodex Points 68

Warpzit a raison. Cela résout également le problème du titre lorsque l'orientation de l'appareil est modifiée. De plus, si vous utilisez le support v7 pour la barre d'action, vous pouvez obtenir la barre d'action à partir du fragment comme ceci :

@Override
public void onResume() {
    super.onResume();
    ((ActionBarActivity)getActivity()).getSupportActionBar().setTitle("Home");
}

0 votes

+1 pour le support v7. Je pense que chaque fois qu'une réponse Android est donnée, la personne qui répond devrait tenir compte du support. À l'heure actuelle, pour atteindre une couverture de 80 % des appareils, vous DEVEZ revenir à l'API 16. Dans la plupart des cas, cela nécessite l'utilisation des bibliothèques compat.

1 votes

J'ai mis votre code dans public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) et a bien fonctionné.

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:

X