getSupportActionBar de dentro de Fragment ActionBarCompat

102

Estou iniciando um novo projeto que usa a biblioteca de suporte AppCompat/ActionBarCompatin v7. Estou tentando descobrir como usar o getSupportActionBarde dentro de um fragmento. Minha atividade que hospeda o fragmento se estende ActionBarActivity, mas não vejo uma classe de suporte semelhante para fragmentos.

De dentro do meu fragmento

    public class CrimeFragment extends Fragment {
          //...

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

          //...
    }

A página do google para usá-lo ( http://android-developers.blogspot.in/2013/08/actionbarcompat-and-io-2013-app-source.html ) diz que não deve haver alterações para o v4fragmento. Eu preciso transmitir todas as minhas getActivity()chamadas para um ActionBarActivity? Isso parece um design ruim.

Paulo
fonte

Respostas:

287

Após Fragment.onActivityCreated (...) você terá uma atividade válida acessível através de getActivity ().

Você precisará lançá-lo em uma ActionBarActivity e, em seguida, fazer a chamada para getSupportActionBar ().

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

Você precisa do elenco. Não é um design ruim, é compatibilidade com versões anteriores.

Pierre-Antoine LaFayette
fonte
3
Obrigado. Eu esperava que essa não fosse a resposta. Eu esperava que getActionBar () retornasse uma ActionBar v7 para a qual eu lançaria se precisasse de funcionalidade extra. Agora meus fragmentos precisam estar cientes de que tipo de atividade eles estão hospedados.
Paulo
Não, não porque getActionBar () é uma API de atividade que não existe em versões anteriores do SDK (pré-honeycomb). É por isso que precisamos de classes de suporte que espelhem a funcionalidade das novas e aprimoradas classes e APIs em SDKs mais recentes.
Pierre-Antoine LaFayette
@ Pierre-AntoineLaFayette Por que isso tem que ser feito em onAttach ()? Não seria melhor em onActivityCreated ()?
IgorGanapolsky
Sim, uma vez que a primeira chamada para getSupportActionBar () inicializará a ActionBar examinando as visualizações na atividade, provavelmente é melhor que essa chamada seja feita em onActivityCreated (). Eu estava apenas tentando indicar que você precisa esperar até que o fragmento tenha uma atividade. Vou atualizar a resposta.
Pierre-Antoine LaFayette
2
Use AppCompatActivity em vez de ActionBarActivity
Aparajita Sinha
37

Embora esta questão já tenha uma resposta aceita, devo ressaltar que não é totalmente correta: ligar getSupportActionBar()de Fragment.onAttach()causará um NullPointerExceptionquando a atividade for rotacionada.

Resposta curta:

Use ((ActionBarActivity)getActivity()).getSupportActionBar()em onActivityCreated()(ou qualquer ponto posterior em seu ciclo de vida) em vez de onAttach().

Resposta longa:

O motivo é que, se um ActionBarActivityfor recriado após uma rotação, ele restaurará todos os fragmentos antes de realmente criar o ActionBarobjeto.

Código-fonte para ActionBarActivityna support-v7biblioteca:

@Override
protected void onCreate(Bundle savedInstanceState) {
    mImpl = ActionBarActivityDelegate.createDelegate(this);
    super.onCreate(savedInstanceState);
    mImpl.onCreate(savedInstanceState);
}
  • ActionBarActivityDelegate.createDelegate()cria o mImplobjeto dependendo da versão do Android.
  • super.onCreate()é FragmentActivity.onCreate(), que restaura quaisquer fragmentos anteriores após uma rotação ( FragmentManagerImpl.dispatchCreate(), & c).
  • mImpl.onCreate(savedInstanceState)é ActionBarActivityDelegate.onCreate(), que lê a mHasActionBarvariável do estilo da janela.
  • Antes que mHasActionBarseja verdade, getSupportActionBar()sempre vai voltar null.

Fonte para 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
fonte
2
ActionBarActivityestá obsoleto. Use em AppCompatActivityvez disso
Saman Sattari
29

Se alguém usar com.android.support:appcompat-v7: e AppCompatActivity como atividade, isso funcionará

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

em sua tag fragment.xmladicionar Toolbarda biblioteca de suporte

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

Agora, como podemos controlar isso da MyFragmentaula? vamos ver

dentro da onCreateViewfunção adicione o seguinte

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

e se você deseja adicionar itemsà barra de ferramentas dentro de MyFragment você mustadicione dentro linha de onCreateViewfunção

        setHasOptionsMenu(true);

esta linha é importante, se você esquecê-la, o android não irá preencher os itens do menu.

suponha que os identificamos em menu/fragment_menu.xml

depois disso, substitua as seguintes funções

@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 isto ajude

Basheer AL-MOMANI
fonte
5

Como uma resposta atualizada para a resposta de Pierre-Antoine LaFayette

ActionBarActivity está obsoleto; use ao AppCompatActivityinvés

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

Para aqueles que usam kotlin,

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