getSupportActionBar desde el interior de Fragment ActionBarCompat

102

Estoy empezando un nuevo proyecto que utiliza el AppCompat/ActionBarCompatde v7biblioteca de soporte. Estoy tratando de averiguar cómo usar el getSupportActionBardesde dentro de un fragmento. Mi actividad que aloja el fragmento se extiende ActionBarActivity, pero no veo una clase de soporte similar para Fragmentos.

Desde dentro de mi fragmento

    public class CrimeFragment extends Fragment {
          //...

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

          //...
    }

La página de Google para usarlo ( http://android-developers.blogspot.in/2013/08/actionbarcompat-and-io-2013-app-source.html ) dice que no debería haber cambios para el v4fragmento. ¿Necesito enviar todas mis getActivity()llamadas a un ActionBarActivity? Eso parece un mal diseño.

Pablo
fuente

Respuestas:

287

Después de Fragment.onActivityCreated (...) , tendrá una actividad válida accesible a través de getActivity ().

Deberá convertirlo en ActionBarActivity y luego realizar la llamada a getSupportActionBar ().

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

Necesitas el yeso. No es un diseño deficiente, es compatibilidad con versiones anteriores.

Pierre-Antoine LaFayette
fuente
3
Gracias. Esperaba que esta no fuera la respuesta. Esperaba que tal vez getActionBar () devolviera una barra de acción v7 a la que enviaría si necesitaba la funcionalidad adicional. Ahora mis Fragmentos deben saber en qué tipo de actividad están alojados.
Paul
No, no es así porque getActionBar () es una API de actividad que no existe en versiones anteriores del SDK (pre-honeycomb). Es por eso que necesitamos clases de soporte que reflejen la funcionalidad de las clases y API nuevas y mejoradas en los SDK más recientes.
Pierre-Antoine LaFayette
@ Pierre-AntoineLaFayette ¿Por qué hay que hacer esto en onAttach ()? ¿No sería mejor en onActivityCreated ()?
IgorGanapolsky
Sí, dado que la primera llamada a getSupportActionBar () inicializará ActionBar buscando las vistas en la actividad, probablemente sea mejor que esta llamada se realice en onActivityCreated (). Más bien estaba tratando de indicar que debe esperar hasta que el fragmento tenga actividad. Actualizaré la respuesta.
Pierre-Antoine LaFayette
2
Use AppCompatActivity en lugar de ActionBarActivity
Aparajita Sinha
37

Si bien esta pregunta ya tiene una respuesta aceptada, debo señalar que no es del todo correcta: llamar getSupportActionBar()desde Fragment.onAttach()causará un NullPointerExceptioncuando se rota la actividad.

Respuesta corta:

Úselo ((ActionBarActivity)getActivity()).getSupportActionBar()en onActivityCreated()(o en cualquier punto posterior de su ciclo de vida) en lugar de onAttach().

Respuesta larga:

La razón es que si ActionBarActivityse recrea después de una rotación, restaurará todos los Fragmentos antes de crear realmente el ActionBarobjeto.

Código fuente para ActionBarActivityen la support-v7biblioteca:

@Override
protected void onCreate(Bundle savedInstanceState) {
    mImpl = ActionBarActivityDelegate.createDelegate(this);
    super.onCreate(savedInstanceState);
    mImpl.onCreate(savedInstanceState);
}
  • ActionBarActivityDelegate.createDelegate()crea el mImplobjeto según la versión de Android.
  • super.onCreate()es FragmentActivity.onCreate(), que restaura los fragmentos anteriores después de una rotación ( FragmentManagerImpl.dispatchCreate(), & c).
  • mImpl.onCreate(savedInstanceState)es ActionBarActivityDelegate.onCreate(), que lee la mHasActionBarvariable del estilo de la ventana.
  • Antes mHasActionBares verdad, getSupportActionBar()siempre volverá null.

Fuente de 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
fuente
2
ActionBarActivityes obsoleto. Úselo en su AppCompatActivitylugar
Saman Sattari
29

Si alguien usa com.android.support:appcompat-v7: y AppCompatActivity como actividad, esto funcionará

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

en su fragment.xmlcomplemento Toolbaretiqueta de la biblioteca de soporte

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

Ahora bien, ¿cómo podemos controlarlo desde MyFragmentclase? veamos

dentro de la onCreateViewfunción agregue lo siguiente

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

y si desea agregar itemsa la barra de herramientas dentro de MyFragment usted, mustagregue esta línea dentro de la onCreateViewfunción

        setHasOptionsMenu(true);

Esta línea es importante, si la olvida, Android no completará los elementos de su menú.

asumimos que los identificamos en menu/fragment_menu.xml

después de eso, anula las siguientes funciones

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

espero que esto ayude

Basheer AL-MOMANI
fuente
5

Como respuesta actualizada a la respuesta de Pierre-Antoine LaFayette

ActionBarActivity está en desuso; usar AppCompatActivityen su lugar

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

Para aquellos que usan kotlin,

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