Volte programaticamente ao fragmento anterior no backstack

218

Digamos que eu tenha uma atividade que tenha fragmentos adicionados programaticamente:

private void animateToFragment(Fragment newFragment, String tag) {
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.replace(R.id.fragment_container, newFragment, tag);
    ft.addToBackStack(null);
    ft.commit();
}

Qual é a melhor maneira de retornar ao fragmento anterior que estava visível?

Encontrei a funcionalidade Trigger back-button no clique no botão no Android, mas estou pensando que simular um evento de tecla back não é o caminho certo para isso (e também não consigo fazê-lo funcionar):

dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));

Ligar finish()apenas fecha a atividade na qual não estou interessado.

Existe uma maneira melhor de fazer isso?

Aske B.
fonte

Respostas:

354

Veja os getFragmentManager().popBackStack()métodos (existem vários por onde escolher)

http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack ()

sem cola
fonte
91
getFragmentManager().popBackStackImmediate();fez o truque. Obrigado.
Aske B.
1
Onde eu colocaria esse método? No meu ouvinte da guia?
rasen58
1
sem ver o código, é difícil dizer ... mas deve ir na seção do código que é executada quando você deseja "fechar" o fragmento atual e retornar ao fragmento anterior.
stuckless
1
que tal getSupportFragmentManager ()
ViliusK:
5
Não se esqueça de adicionar "addToBackStack (" tag ")" no seu código. "fragmentManager.beginTransaction (). replace (R.id.content_frame, fragmento) .addToBackStack (" tag "). commit ();" se você escrever addToBackStack (null), ele cuidará disso sozinho, mas se você der uma tag, deverá manipulá-la manualmente.
Khaled Saif
129

Para elaborar as outras respostas fornecidas, esta é a minha solução (colocada em uma Atividade):

@Override
public void onBackPressed(){
    FragmentManager fm = getFragmentManager();
    if (fm.getBackStackEntryCount() > 0) {
        Log.i("MainActivity", "popping backstack");
        fm.popBackStack();
    } else {
        Log.i("MainActivity", "nothing on backstack, calling super");
        super.onBackPressed();  
    }
}
Kyle Falconer
fonte
5
e por que isso está acontecendo? No exemplo de fragmento developer.android.com/training/basics/fragments/index.html, eles não estão substituindo o evento onbackpressed e, no entanto, podem recuperar o fragmento. Eu usei trasaction.addToBackStack (null); mas nada acontece. Você pode explicar o porquê?
Murtaza Khursheed Hussain
@MurtazaHussain você provavelmente deve fazer uma nova pergunta se quiser ajuda com isso. É um pouco difícil ver o que está acontecendo sem olhar para mais código.
Kyle Falconer
2
No meu caso, eu tive que fazer fm.getBackStackEntryCount() > 1para retornar a atividade quando houver apenas o primeiro fragmento na pilha.
Facundo Olano
3
O Android já faz isso por você: "Quando há objetos FragmentTransaction na pilha traseira e o usuário pressiona o botão Voltar, o FragmentManager retira a transação mais recente da pilha traseira e executa a ação inversa (como remover um fragmento se a transação adicionou). " (Source)
artkoenig 15/10
29

Quando estamos atualizando / adicionando os fragmentos,

Deve incluir o .addToBackStack().

getSupportFragmentManager().beginTransaction()
    .add(detailFragment, "detail") // Add this transaction to the back stack (name is an optional name for this back stack state, or null).
    .addToBackStack(null)
    .commit();

Depois disso, se dermos o getFragments.popBackStackImmediate(), retornará true se adicionarmos / atualizarmos os fragmentos e voltarmos para a tela atual.

Jabeer
fonte
7

Adicione essas linhas ao seu método onBackPressed (). O método popBackStackImmediate () o levará de volta ao fragmento anterior se você tiver algum fragmento na pilha traseira `

if(getFragmentManager().getBackStackEntryCount() > 0){
     getFragmentManager().popBackStackImmediate();
}
else{
    super.onBackPressed();
}

`

Avijit Biswas
fonte
5

Esta solução funciona perfeitamente para a navegação de fragmentos com base na barra inferior quando você deseja fechar o aplicativo quando pressionado novamente no fragmento primário.

Por outro lado, quando você está abrindo o fragmento secundário (fragmento em fragmento) que é definido como "DetalhadaPizza" no meu código, ele retornará o estado anterior do fragmento primário. Felicidades !

Atividades internas nas costas pressionadas colocam o seguinte:

Fragment home = getSupportFragmentManager().findFragmentByTag("DetailedPizza");

if (home instanceof FragmentDetailedPizza && home.isVisible()) {
    if (getFragmentManager().getBackStackEntryCount() != 0) {
        getFragmentManager().popBackStack();
    } else {
        super.onBackPressed();
    }
} else {
    //Primary fragment
    moveTaskToBack(true);
}

E inicie o outro fragmento assim:

Fragment someFragment = new FragmentDetailedPizza();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container_body, someFragment, "DetailedPizza");
transaction.addToBackStack("DetailedPizza");
transaction.commit();
Giedrius Šlikas
fonte
3

Essas respostas não funcionarão se eu não tiver addToBackStack () adicionado à minha transação de fragmento, mas você pode usar:

getActivity().onBackPressed();

do seu fragmento para voltar um passo;

Biplob Das
fonte
1

Programaticamente volte ao fragmento anterior usando o código a seguir.

if ( getFragmentManager().getBackStackEntryCount() > 0) 
{
          getFragmentManager().popBackStack();
          return;
}
super.onBackPressed();
Piyush MandaliYa
fonte
1

Para fazer com que o fragmento volte novamente, basta adicionar o fragmento ao backstack que você deseja pressionar novamente, por exemplo:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Fragment fragment = new LoginFragment();
        //replacing the fragment
        if (fragment != null) {
            FragmentTransaction ft = ((FragmentActivity)getContext()).getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.content_frame, fragment);
            ft.addToBackStack("SignupFragment");
            ft.commit();
        }
    }
});

No caso acima, eu estou abrindo LoginFragmentquando Button buttoné pressionada, agora o usuário está em SignupFragment. Então, se addToBackStack(TAG)for chamado, onde TAG = "SignupFragment", quando o botão Voltar for pressionado LoginFragment, voltaremos para SignUpFragment.

Feliz codificação!

Saurabh Singh
fonte
Eu acho que o TAG não afeta, talvez até nulo.
CoolMind
1

Ao adicionar o fragment_tran.addToBackStack(null)último fragmento, sou capaz de voltar ao último fragmento.

adicionando novo fragmento :

view.findViewById(R.id.changepass).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
            transaction.replace(R.id.container, new ChangePassword());
            transaction.addToBackStack(null);
            transaction.commit();
        }
    });
Baljinder Maan
fonte
1

Eu vim aqui procurando ou com a mesma idéia e, enquanto isso, criei a minha própria, que acredito que não é tão ruim e funciona com o ViewPager.

Então, o que fiz foi substituir o método onBackPressed na atividade pai que contém o viewPager e configurá-lo para voltar sempre menos 1 posição até atingir o primeiro fragmento e depois fechar a atividade.

@Override
public void onBackPressed() {
    if(viewPager.getCurrentItem()>0){
        viewPager.setCurrentItem(viewPager.getCurrentItem()-1);
    } else {
        super.onBackPressed();
        this.close();
    }
}

private void close(){
    this.finish();
}

Isso pode ter uma queda, pois só volta um caminho à esquerda de cada vez; portanto, pode não funcionar muito bem se houver guias e você mudar de posição com os fragmentos ignorados (passando de 0 a 2 e pressionando para trás). 1, em vez de 0)

No meu caso, com 2 fragmentos no viewPager sem guias, ele funciona bem.

Grzesiek Eman
fonte
Pergunta semelhante já foi respondida. stackoverflow.com/questions/10863572/…
AtifSayings
0

Experimente o código abaixo:

@Override
    public void onBackPressed() {
        Fragment myFragment = getSupportFragmentManager().findFragmentById(R.id.container);
        if (myFragment != null && myFragment instanceof StepOneFragment) {
            finish();
        } else {
            if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
                getSupportFragmentManager().popBackStack();
            } else {
                super.onBackPressed();
            }
        }
    }
adarsh
fonte