getSupportActionBar z wnętrza fragmentu ActionBarCompat

102

Zaczynam nowy projekt, który używa AppCompat/ActionBarCompatw v7bibliotece wsparcia. Próbuję wymyślić, jak korzystać getSupportActionBarz fragmentu. Moja aktywność, która obsługuje ten fragment, jest rozszerzona ActionBarActivity, ale nie widzę podobnej klasy obsługi dla fragmentów.

Z mojego fragmentu

    public class CrimeFragment extends Fragment {
          //...

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

          //...
    }

Strona google dotycząca korzystania z niego ( http://android-developers.blogspot.in/2013/08/actionbarcompat-and-io-2013-app-source.html ) mówi, że nie powinno być żadnych zmian w tym v4fragmencie. Czy muszę przekazywać wszystkie getActivity()połączenia na numer ActionBarActivity? To wygląda na kiepski projekt.

Paweł
źródło

Odpowiedzi:

288

Po Fragment.onActivityCreated (...) będziesz mieć prawidłowe działanie dostępne przez getActivity ().

Będziesz musiał rzucić go na ActionBarActivity, a następnie wywołać metodę getSupportActionBar ().

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

Potrzebujesz obsady. To nie jest kiepski projekt, to kompatybilność wsteczna.

Pierre-Antoine LaFayette
źródło
3
Dzięki. Miałem nadzieję, że to nie będzie odpowiedź. Miałem nadzieję, że metoda getActionBar () zwróci pasek ActionBar w wersji 7, na który rzutowałbym, gdybym potrzebował dodatkowej funkcjonalności. Teraz moje fragmenty muszą być świadome, w jakim rodzaju działania są hostowane.
Paul,
Nie, nie jest, ponieważ getActionBar () jest interfejsem API działań, które nie istnieje w starszych wersjach SDK (pre-honeycomb). Dlatego potrzebujemy klas pomocniczych, które odzwierciedlają funkcjonalność nowych i ulepszonych klas i interfejsów API w nowszych pakietach SDK.
Pierre-Antoine LaFayette
@ Pierre-AntoineLaFayette Dlaczego trzeba to zrobić w onAttach ()? Czy nie byłoby lepiej w onActivityCreated ()?
Igor Ganapolsky
Tak, ponieważ pierwsze wywołanie metody getSupportActionBar () zainicjuje ActionBar poprzez wyszukanie widoków w działaniu, prawdopodobnie lepiej jest, aby to wywołanie zostało wykonane w onActivityCreated (). Chciałem tylko wskazać, że trzeba poczekać, aż fragment zacznie działać. Zaktualizuję odpowiedź.
Pierre-Antoine LaFayette
2
Użyj AppCompatActivity zamiast ActionBarActivity
Aparajita Sinha
37

Chociaż to pytanie ma już zaakceptowaną odpowiedź, muszę zaznaczyć, że nie jest całkowicie poprawne: wywołanie getSupportActionBar()z Fragment.onAttach()spowoduje NullPointerException, że działanie zostanie obrócone.

Krótka odpowiedź:

Użyj ((ActionBarActivity)getActivity()).getSupportActionBar()w onActivityCreated()(lub dowolnym późniejszym momencie w jego cyklu życia) zamiast onAttach().

Długa odpowiedź:

Powodem jest to, że jeśli obiekt ActionBarActivityzostanie odtworzony po obróceniu, przywróci wszystkie fragmenty przed faktycznym utworzeniem ActionBarobiektu.

Kod źródłowy ActionBarActivityw support-v7bibliotece:

@Override
protected void onCreate(Bundle savedInstanceState) {
    mImpl = ActionBarActivityDelegate.createDelegate(this);
    super.onCreate(savedInstanceState);
    mImpl.onCreate(savedInstanceState);
}
  • ActionBarActivityDelegate.createDelegate()tworzy mImplobiekt w zależności od wersji Androida.
  • super.onCreate()jest FragmentActivity.onCreate(), który przywraca wszystkie poprzednie fragmenty po rotacji ( FragmentManagerImpl.dispatchCreate(), & c).
  • mImpl.onCreate(savedInstanceState)is ActionBarActivityDelegate.onCreate(), który odczytuje mHasActionBarzmienną ze stylu okna.
  • Zanim mHasActionBarto prawda, getSupportActionBar()zawsze wróci null.

Źródło 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
źródło
2
ActionBarActivityjest przestarzałe. Użyj AppCompatActivityzamiast tego
Saman Sattari
29

Jeśli ktoś używa com.android.support:appcompat-v7: i AppCompatActivity jako aktywności, to zadziała

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);
Amir
źródło
5

w fragment.xmldodanym Toolbartagu z biblioteki wsparcia

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

Jak możemy to kontrolować z MyFragmentklasy? Zobaczmy

wewnątrz onCreateViewfunkcji dodaj następujące elementy

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

a jeśli chcesz dodać itemsdo paska narzędzi wewnątrz MyFragment , mustdodaj tę linię wewnątrz onCreateViewfunkcji

        setHasOptionsMenu(true);

ta linia jest ważna, jeśli ją zapomnisz, Android nie zapełni twoich pozycji menu.

załóżmy, że identyfikujemy je w menu/fragment_menu.xml

po tym nadpisuje następujące funkcje

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

mam nadzieję że to pomoże

Basheer AL-MOMANI
źródło
5

Jako zaktualizowana odpowiedź na odpowiedź Pierre-Antoine LaFayette

ActionBarActivity jest przestarzałe; użyj AppCompatActivityzamiast tego

((AppCompatActivity)getActivity()).getSupportActionBar();
Dasser Basyouni
źródło
3

Dla osób używających kotlin,

(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)
GzDevs
źródło