getSupportActionBar aus dem Fragment ActionBarCompat

102

Ich starte ein neues Projekt, das die AppCompat/ActionBarCompatIn- v7Support-Bibliothek verwendet. Ich versuche herauszufinden, wie man das getSupportActionBaraus einem Fragment heraus verwendet. Meine Aktivität, die das Fragment hostet, wird erweitert ActionBarActivity, aber ich sehe keine ähnliche Unterstützungsklasse für Fragmente.

Aus meinem Fragment heraus

    public class CrimeFragment extends Fragment {
          //...

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

          //...
    }

Die Google-Seite für die Verwendung ( http://android-developers.blogspot.in/2013/08/actionbarcompat-and-io-2013-app-source.html ) gibt an, dass für das v4Fragment keine Änderungen vorgenommen werden sollten . Muss ich alle meine getActivity()Anrufe an einen ActionBarActivitysenden? Das scheint schlechtes Design zu sein.

Paul
quelle

Antworten:

287

Nach Fragment.onActivityCreated (...) haben Sie eine gültige Aktivität, auf die Sie über getActivity () zugreifen können.

Sie müssen es in eine ActionBarActivity umwandeln und dann getSupportActionBar () aufrufen.

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

Du brauchst die Besetzung. Es ist kein schlechtes Design, es ist abwärtskompatibel.

Pierre-Antoine LaFayette
quelle
3
Vielen Dank. Ich hatte gehofft, dass dies nicht die Antwort sein würde. Ich hatte gehofft, dass getActionBar () eine v7-ActionBar zurückgeben würde, in die ich umwandeln würde, wenn ich die zusätzliche Funktionalität benötige. Jetzt müssen meine Fragmente wissen, in welcher Art von Aktivität sie gehostet werden
Paul
Nein, weil getActionBar () eine Aktivitäts-API ist, die in älteren Versionen des SDK (Pre-Honeycomb) nicht vorhanden ist. Aus diesem Grund benötigen wir Support-Klassen, die die Funktionalität der neuen und verbesserten Klassen und APIs in neueren SDKs widerspiegeln.
Pierre-Antoine LaFayette
@ Pierre-AntoineLaFayette Warum muss dies in onAttach () erfolgen? Wäre es nicht besser in onActivityCreated ()?
Igor Ganapolsky
Ja, da der erste Aufruf von getSupportActionBar () die ActionBar durch Nachschlagen der Ansichten in der Aktivität initialisiert, ist es wahrscheinlich besser, diesen Aufruf in onActivityCreated () durchzuführen. Ich habe nur versucht anzuzeigen, dass Sie warten müssen, bis das Fragment eine Aktivität hat. Ich werde die Antwort aktualisieren.
Pierre-Antoine LaFayette
2
Verwenden Sie AppCompatActivity anstelle von ActionBarActivity
Aparajita Sinha
37

Obwohl diese Frage bereits eine akzeptierte Antwort hat, muss ich darauf hinweisen, dass sie nicht ganz richtig ist: Ein Anruf getSupportActionBar()von Fragment.onAttach()führt zu einemNullPointerException Wenn Sie wenn die Aktivität gedreht wird.

Kurze Antwort:

Verwenden Sie ((ActionBarActivity)getActivity()).getSupportActionBar()in onActivityCreated()(oder einen beliebigen Punkt danach in seinem Lebenszyklus) anstelle vononAttach() .

Lange Antwort:

Der Grund dafür ist, dass bei einer ActionBarActivityNeuerstellung nach einer Rotation alle Fragmente zuvor wiederhergestellt werden das ActionBarObjekt tatsächlich erstellt wird.

Quellcode für ActionBarActivityin der support-v7Bibliothek:

@Override
protected void onCreate(Bundle savedInstanceState) {
    mImpl = ActionBarActivityDelegate.createDelegate(this);
    super.onCreate(savedInstanceState);
    mImpl.onCreate(savedInstanceState);
}
  • ActionBarActivityDelegate.createDelegate() schafft die mImpl Objekt abhängig von der Android-Version.
  • super.onCreate()ist FragmentActivity.onCreate(), wodurch alle vorherigen Fragmente nach einer Drehung wiederhergestellt werden (FragmentManagerImpl.dispatchCreate() , & c).
  • mImpl.onCreate(savedInstanceState) ist ActionBarActivityDelegate.onCreate() , das die mHasActionBarVariable aus dem Fensterstil liest .
  • Vorher mHasActionBarist wahr, getSupportActionBar()wird immer zurückkehrennull .

Quelle für 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
quelle
2
ActionBarActivityist veraltet. Verwenden Sie AppCompatActivitystattdessen
Saman Sattari
29

Wenn jemand com.android.support:appcompat-v7: und AppCompatActivity als Aktivität verwendet, funktioniert dies

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

in Ihrem fragment.xmlAdd- ToolbarTag aus der Support-Bibliothek

 <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" />

Wie können wir es nun vom MyFragmentUnterricht aus steuern ? Mal schauen

Innerhalb der onCreateViewFunktion fügen Sie Folgendes hinzu

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);

und wenn Sie zur itemsSymbolleiste hinzufügen möchten, fügen MyFragment Sie mustdiese Zeile innerhalb der onCreateViewFunktion hinzu

        setHasOptionsMenu(true);

Diese Zeile ist wichtig, wenn Sie es vergessen, wird Android Ihre Menüelemente nicht füllen.

Nehmen wir an, wir identifizieren sie in menu/fragment_menu.xml

Danach überschreiben Sie die folgenden Funktionen

@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;
}

hoffe das hilft

Basheer AL-MOMANI
quelle
5

Als aktualisierte Antwort auf die Antwort von Pierre-Antoine LaFayette

ActionBarActivity ist veraltet. Verwenden Sie AppCompatActivitystattdessen

((AppCompatActivity)getActivity()).getSupportActionBar();
Dasser Basyouni
quelle
3

Für diejenigen, die Kotlin verwenden,

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