getSupportActionBar depuis l'intérieur du fragment ActionBarCompat

102

Je commence un nouveau projet qui utilise la AppCompat/ActionBarCompatdans la v7bibliothèque de soutien. J'essaie de comprendre comment utiliser le à getSupportActionBarpartir d'un fragment. Mon activité qui héberge le fragment s'étend ActionBarActivity, mais je ne vois pas de classe de support similaire pour les fragments.

De l'intérieur de mon fragment

    public class CrimeFragment extends Fragment {
          //...

          getActivity().getSupportActionBar().setSubtitle(R.string.subtitle); // getSupportActionBar is not defined in the v4 version of Fragment

          //...
    }

La page Google pour l'utiliser ( http://android-developers.blogspot.in/2013/08/actionbarcompat-and-io-2013-app-source.html ) indique qu'il ne devrait y avoir aucun changement pour le v4fragment. Dois-je envoyer tous mes getActivity()appels à un ActionBarActivity? Cela semble être une mauvaise conception.

Paul
la source

Réponses:

287

Après Fragment.onActivityCreated (...), vous aurez une activité valide accessible via getActivity ().

Vous devrez le convertir en ActionBarActivity, puis appeler getSupportActionBar ().

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);

Vous avez besoin du casting. Ce n'est pas une mauvaise conception, c'est une compatibilité ascendante.

Pierre-Antoine LaFayette
la source
3
Merci. J'espérais que ce ne serait pas la réponse. J'espérais peut-être que getActionBar () renverrait une ActionBar v7 vers laquelle je jetterais si j'avais besoin de fonctionnalités supplémentaires. Maintenant, mes fragments doivent savoir dans quel type d'activité ils sont hébergés.
Paul
Non, car getActionBar () est une API d'activité qui n'existe pas sur les anciennes versions du SDK (pré-honeycomb). C'est pourquoi nous avons besoin de classes de support qui reflètent les fonctionnalités des classes et API nouvelles et améliorées dans les SDK les plus récents.
Pierre-Antoine LaFayette
@ Pierre-AntoineLaFayette Pourquoi cela doit-il être fait dans onAttach ()? Ne serait-ce pas mieux dans onActivityCreated ()?
IgorGanapolsky
Oui puisque le premier appel à getSupportActionBar () initialisera l'ActionBar en recherchant les vues dans l'activité, il est probablement préférable que cet appel soit fait dans onActivityCreated (). J'essayais plus simplement d'indiquer que vous devez attendre que le fragment ait une activité. Je mettrai à jour la réponse.
Pierre-Antoine LaFayette
2
Utilisez AppCompatActivity au lieu d'ActionBarActivity
Aparajita Sinha
37

Bien que cette question ait déjà une réponse acceptée, je dois souligner qu'elle n'est pas totalement correcte: appeler à getSupportActionBar()partir de Fragment.onAttach()provoquera une NullPointerExceptionrotation de l'activité.

Réponse courte:

Utilisez ((ActionBarActivity)getActivity()).getSupportActionBar()dans onActivityCreated()(ou à tout autre moment après dans son cycle de vie) au lieu de onAttach().

Longue réponse:

La raison en est que si un ActionBarActivityest recréé après une rotation, il restaurera tous les fragments avant de créer réellement l' ActionBarobjet.

Code source pour ActionBarActivitydans la support-v7bibliothèque:

@Override
protected void onCreate(Bundle savedInstanceState) {
    mImpl = ActionBarActivityDelegate.createDelegate(this);
    super.onCreate(savedInstanceState);
    mImpl.onCreate(savedInstanceState);
}
  • ActionBarActivityDelegate.createDelegate()crée l' mImplobjet en fonction de la version d'Android.
  • super.onCreate()is FragmentActivity.onCreate(), qui restaure tous les fragments précédents après une rotation ( FragmentManagerImpl.dispatchCreate(), & c).
  • mImpl.onCreate(savedInstanceState)is ActionBarActivityDelegate.onCreate(), qui lit la mHasActionBarvariable à partir du style de fenêtre.
  • Avant mHasActionBarc'est vrai, getSupportActionBar()reviendra toujours null.

Source pour ActionBarActivityDelegate.getSupportActionBar():

final ActionBar getSupportActionBar() {
    // The Action Bar should be lazily created as mHasActionBar or mOverlayActionBar
    // could change after onCreate
    if (mHasActionBar || mOverlayActionBar) {
        if (mActionBar == null) {
            ... creates the action bar ...
        }
    } else {
        // If we're not set to have a Action Bar, null it just in case it's been set
        mActionBar = null;
    }
    return mActionBar;
}
matiash
la source
2
ActionBarActivityest obsolète. Utiliser à la AppCompatActivityplace
Saman Sattari
29

Si quelqu'un utilise com.android.support:appcompat-v7: et AppCompatActivity comme activité, cela fonctionnera

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);
Amir
la source
5

dans votre fragment.xmlajouter une Toolbarbalise à partir de la bibliothèque de support

 <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

Maintenant, comment pouvons-nous le contrôler depuis la MyFragmentclasse? Voyons voir

onCreateViewfonction à l' intérieur ajouter ce qui suit

mToolbar = (Toolbar) view.findViewById(R.id.toolbar);
((AppCompatActivity)getActivity()).setSupportActionBar(mToolbar);

//add this line if you want to provide Up Navigation but don't forget to to 
//identify parent activity in manifest file
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);

et si vous voulez ajouter itemsà la barre d' outils à l' intérieur MyFragment vous mustajoutez cette ligne dans la onCreateViewfonction

        setHasOptionsMenu(true);

cette ligne est importante, si vous l'oubliez, Android ne remplira pas vos éléments de menu.

supposons que nous les identifions dans menu/fragment_menu.xml

après cela, remplacez les fonctions suivantes

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

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    switch (id) {
        case R.id.action_1:
            // do stuff
            return true;

        case R.id.action_2:
            // do more stuff
            return true;
    }

    return false;
}

J'espère que cela t'aides

Basheer AL-MOMANI
la source
5

Une réponse actualisée à la réponse de Pierre-Antoine LaFayette

ActionBarActivity est obsolète; utiliser à la AppCompatActivityplace

((AppCompatActivity)getActivity()).getSupportActionBar();
Dasser Basyouni
la source
3

Pour ceux qui utilisent kotlin,

(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)
GzDevs
la source