Com o Android 4.2, a biblioteca de suporte tem suporte para fragmentos aninhados, veja aqui . Eu brinquei com ele e encontrei um comportamento / bug interessante em relação à pilha de retorno e getChildFragmentManager () . Ao usar getChildFragmentManager () e addToBackStack (String name), ao pressionar o botão Voltar, o sistema não executa a pilha de volta para o fragmento anterior. Por outro lado, ao usar getFragmentManager () e addToBackStack (String name), ao pressionar o botão Voltar o sistema retorna ao fragmento anterior.
Para mim, esse comportamento é inesperado. Ao pressionar o botão Voltar em meu dispositivo, espero que o último fragmento adicionado à pilha de retorno seja exibido, mesmo que o fragmento tenha sido adicionado à pilha de retorno no gerenciador de fragmentos dos filhos.
Este comportamento está correto? Este comportamento é um bug? Existe uma solução alternativa para esse problema?
código de amostra com getChildFragmentManager ():
public class FragmentceptionActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
final FrameLayout wrapper1 = new FrameLayout(this);
wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper1.setId(1);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 0;
final TextView text = new TextView(this);
text.setLayoutParams(params);
text.setText("fragment 1");
wrapper1.addView(text);
setContentView(wrapper1);
getSupportFragmentManager().beginTransaction().addToBackStack(null)
.add(1, new Fragment1()).commit();
}
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper2 = new FrameLayout(getActivity());
wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper2.setId(2);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 100;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 2");
wrapper2.addView(text);
return wrapper2;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(2, new Fragment2()).commit();
}
}
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper3 = new FrameLayout(getActivity());
wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper3.setId(3);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 200;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 3");
wrapper3.addView(text);
return wrapper3;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getChildFragmentManager().beginTransaction().addToBackStack(null)
.add(3, new Fragment3()).commit();
}
}
public class Fragment3 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper4 = new FrameLayout(getActivity());
wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper4.setId(4);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 300;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 4");
wrapper4.addView(text);
return wrapper4;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getChildFragmentManager().beginTransaction().addToBackStack(null)
.add(4, new Fragment4()).commit();
}
}
public class Fragment4 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper5 = new FrameLayout(getActivity());
wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper5.setId(5);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 400;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 5");
wrapper5.addView(text);
return wrapper5;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
}
código de amostra com getFragmentManager ():
public class FragmentceptionActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
final FrameLayout wrapper1 = new FrameLayout(this);
wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper1.setId(1);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 0;
final TextView text = new TextView(this);
text.setLayoutParams(params);
text.setText("fragment 1");
wrapper1.addView(text);
setContentView(wrapper1);
getSupportFragmentManager().beginTransaction().addToBackStack(null)
.add(1, new Fragment1()).commit();
}
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper2 = new FrameLayout(getActivity());
wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper2.setId(2);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 100;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 2");
wrapper2.addView(text);
return wrapper2;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(2, new Fragment2()).commit();
}
}
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper3 = new FrameLayout(getActivity());
wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper3.setId(3);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 200;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 3");
wrapper3.addView(text);
return wrapper3;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(3, new Fragment3()).commit();
}
}
public class Fragment3 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper4 = new FrameLayout(getActivity());
wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper4.setId(4);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 300;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 4");
wrapper4.addView(text);
return wrapper4;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(4, new Fragment4()).commit();
}
}
public class Fragment4 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper5 = new FrameLayout(getActivity());
wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper5.setId(5);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 400;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 5");
wrapper5.addView(text);
return wrapper5;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
}
Respostas:
Esta solução pode ser uma versão melhor da resposta @Sean:
Novamente, preparei esta solução com base na resposta @Sean acima.
Como @ AZ13 disse, esta solução só é viável em situações de fragmentos filho de um nível. No caso de fragmentos de múltiplos níveis, os trabalhos se tornam um pouco complexos, então eu recomendo que tente esta solução apenas no caso viável que eu disse. =)
Nota: Como o
getFragments
método agora é um método privado, esta solução não funcionará. Você pode verificar os comentários de um link que sugere uma solução para esta situação.fonte
getFragments
agora é público.Parece um bug. Dê uma olhada em: http://code.google.com/p/android/issues/detail?id=40323
Para uma solução alternativa que usei com sucesso (conforme sugerido nos comentários):
fonte
A verdadeira resposta a essa pergunta está na função da Transação de Fragmento chamada setPrimaryNavigationFragment.
Você deve definir esta função no fragmento pai inicial quando a atividade o está adicionando. Eu tenho uma função replaceFragment dentro da minha atividade que se parece com isto:
Isso dá a você o mesmo comportamento de clicar de volta do Fragmento B normal para o Fragmento A, exceto que agora também está nos fragmentos filhos!
fonte
Esta solução pode ser uma versão melhor da resposta @ismailarilik:
Versão de fragmento aninhado
fonte
SupportFragmentManager
e, em vez disso, apenas o padrãoFragmentManager
?Com esta resposta, ele tratará da verificação de retorno recursiva e dará a cada fragmento a chance de substituir o comportamento padrão. Isso significa que você pode fazer com que um fragmento que hospeda um ViewPager faça algo especial, como rolar para a página como uma pilha de retorno, ou rolar para a página inicial e, no próximo verso, pressionar sair.
Adicione isso à sua Activity que estende AppCompatActivity.
Adicione isso ao seu BaseFragment ou à classe da qual todos os seus fragmentos podem ser herdados.
fonte
Este código navegará na árvore de gerenciadores de fragmentos e retornará o último que foi adicionado e que contém fragmentos que podem ser retirados da pilha:
Chame o método:
fonte
O motivo é que sua atividade deriva de FragmentActivity, que lida com o pressionamento da tecla BACK (consulte a linha 173 de FragmentActivity .
Em nosso aplicativo, estou usando um ViewPager (com fragmentos) e cada fragmento pode ter fragmentos aninhados. A maneira como lidei com isso:
void onBackKeyPressed()
Observe também que estou usando
getChildFragmentManager()
os fragmentos para aninhar fragmentos de maneira adequada. Você pode ver uma discussão e uma explicação nesta postagem dos desenvolvedores do Android .fonte
se você estiver usando um fragmento em um fragmento, use
getChildFragmentManager()
se você estiver usando fragmento filho e substituí-lo, use
getParentFragmentManager()
se ambos não estão funcionando para você, tente isso
getActivity().getSupportFragmentManager()
fonte
Consegui controlar a pilha de retorno do fragmento adicionando ao fragmento pai esse método no método onCreate View () e passando a visualização raiz.
O método isEnableFragmentBackStack () é um sinalizador booleano para saber quando estou no fragmento principal ou no próximo.
Certifique-se de que, ao confirmar o fragmento que precisa ter pilha, você deve adicionar o método addToBackstack.
fonte
Esta solução pode ser melhor, porque verifica todos os níveis de fragmentos aninhados:
em sua atividade,
onBackPressed
você pode simplesmente chamá-la desta forma:fonte
Obrigado a todos pela ajuda, esta (versão ajustada) funciona para mim:
NOTA: Você provavelmente também desejará definir a cor de fundo desses fragmentos aninhados com a cor de fundo da janela do tema do aplicativo, já que por padrão eles são transparentes. Um pouco fora do escopo desta questão, mas é realizado resolvendo o atributo android.R.attr.windowBackground e definindo o plano de fundo da visualização Fragment para esse ID de recurso.
fonte
Mais de 5 anos e este assunto ainda é relevante. Se você não quiser usar o fragmentManager.getFragments () devido à sua restrição. Estenda e use as classes abaixo:
NestedFragmentActivity.java
NestedFragment.java
Explicação:
Cada atividade e fragmento estendido das classes acima gerencia sua própria pilha de fundos para cada um de seus filhos, os filhos dos filhos e assim por diante. O backstack é simplesmente um registro de tags / ids de "fragmento ativo". Portanto, a advertência é sempre fornecer uma tag e / ou id para seu fragmento.
Ao adicionar à pilha de retorno em um childFragmentManager, você também precisará chamar "addToParentBackStack ()". Isso garante que a tag / id do fragmento seja adicionada ao fragmento / atividade pai para pops posteriores.
Exemplo:
fonte
Eu implementei corretamente se alguém não encontrou nenhuma resposta até agora
basta adicionar este método em seu fragmento aninhado filho
fonte
Resolvi esse problema mantendo o fragmento aberto atualmente na propriedade de atividade. Então eu substituo o método
É assim que adiciono o fragmento filho ao fragmento atualmente aberto de dentro dele mesmo.
Este é o layout xml do fragmento pai e do fragmento adicionado
fonte
Depois de observar algumas soluções apresentadas aqui, descobri que, para permitir flexibilidade e controle para o fragmento pai quanto ao momento de estourar a pilha ou quando a ação de retorno deve ser ignorada por ela, prefiro usar essa implementação:
Definindo uma interface "ParentFragment":
}
Substituindo "onBackPressed" na atividade pai (ou na BaseActivity):
E então permita que o fragmento pai seja processado como desejar, por exemplo:
Isso permite evitar pensar que há algum fragmento filho legítimo a ser removido ao usar um paginador de visualização, por exemplo (e contagem de entrada de back stack> 0).
fonte
Se você tiver um
DialogFragment
que, por sua vez, possui fragmentos aninhados, a 'solução alternativa' é um pouco diferente. Em vez de definir umonKeyListener
para orootView
, você precisará fazer isso com oDialog
. Além disso, você configurará umDialogInterface.OnKeyListener
e nãoView
aquele. Claro, lembre-seaddToBackStack
!Aqui está o que você deve fazer no onCreateDialog
fonte
Dialog
(nãoDialogFragment
) e o ouvinte que usar éDialogInterface.OnKeyListener
- o código está funcionando e completo (e em uso). Por que você não conta sua situação e talvez eu possa ajudar.para ChildFragments isso funciona.
fonte