O fragmento não está sendo substituído, mas colocado em cima do anterior

104

Atividade:

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

Fragment1 fragment = new Fragment1();
Fragment2 fragment2 = new Fragment2();

transaction.replace(R.id.Fragment1, fragment);
transaction.addToBackStack(null);
transaction.commit();

FragmentTransaction transaction2 = getSupportFragmentManager().beginTransaction();
transaction2.replace(R.id.Fragment1, fragment2);
transaction2.addToBackStack(null);
transaction2.commit();

Código na visualização:

<fragment
    android:id="@+id/Fragment1"
    android:name="com.landa.fragment.Fragment1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_below="@+id/include1" /> 

O problema é que o conteúdo não é realmente substituído - ele é colocado por cima (de modo que se sobrepõe).

Quando clico de volta, o primeiro fragmento é mostrado corretamente (sem o segundo), mas inicialmente ambos estão visíveis (quero que apenas o último esteja visível).

O que estou perdendo aqui?

Ferramenta
fonte
No meu caso o problema era devido ao fato de não estar usando o id apropriado da view do container, ou seja, não estava passando o correto containerViewId(no replacemétodo).
novembro

Respostas:

145

Você está fazendo duas coisas erradas aqui:

  1. Você não pode substituir um fragmento que é colocado estaticamente em um xmlarquivo de layout. Você deve criar um contêiner (por exemplo, a FrameLayout) no layout e, em seguida, adicionar o fragmento de forma programática usando FragmentTransaction.

  2. FragmentTransaction.replaceespera o id do contêiner que contém o fragmento e não o id do fragmento como o primeiro parâmetro. Portanto, você deve passar o primeiro argumento como o id do contêiner ao qual adicionou o primeiro fragmento.

Você pode consultar este link para mais detalhes.

Sapan Diwakar
fonte
17
Usar FrameLayoutcomo recipiente é melhor do que usar LinearLayout.
Marcel Bro
3
Usar um FrameLayout vazio em Activity também resolveu meu problema
Subtle Fox
1
Funciona fazendo isso. Mas então, quando eu inicio meu aplicativo e pressiono imediatamente o botão Voltar, acabo em um estado em que o fragmento está vazio, em vez de sair do aplicativo.
MasterScrat de
@MasterScrat Omita o addTobackStack(..)ao fazer sua transação pela primeira vez. Isso evitará colocar o contêiner FrameLayout vazio na pilha traseira. Você ainda poderá navegar de volta ao fragmento que adicionou.
Alex Meuer 02 de
Aqui está um ótimo vídeo que demonstra sua explicação. youtube.com/watch?v=EbcdMxAIr54
SQL e Java Learner
32

Eu tive um problema semelhante, mas meu problema era que eu estava usando dois gerenciadores de fragmentos diferentes: um de getSupportFragmentManager()e um de getFragmentManager(). Se eu adicionasse um fragmento com o SupportFragmentManagere, em seguida, tentasse substituir o fragmento com o FragmentManager, o fragmento seria apenas adicionado por cima. Eu precisava mudar o código para que o mesmo FragmentManagerfosse usado e isso resolveu o problema.

swbandit
fonte
17

O site do desenvolvedor Android sugere o uso de um FrameLayoutpara carregar fragmentos dinamicamente em tempo de execução. Você codificou o fragmento em seu arquivo xml. Portanto, ele não pode ser removido em tempo de execução, conforme mencionado neste link:

http://developer.android.com/training/basics/fragments/creating.html

este link mostra como adicionar fragmentos por meio de seu programa:

http://developer.android.com/training/basics/fragments/fragment-ui.html

Poonam Anthony
fonte
7

Tive o mesmo problema e vi todas as respostas, mas nenhuma delas continha o meu erro! Antes de tentar substituir o fragmento atual, eu estava mostrando o fragmento padrão no xml da atividade do contêiner assim:

<FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="....ShopFragment"
        android:id="@+id/fragment"
        tools:layout="@layout/fragment_shop" />
</FrameLayout>

depois disso, embora eu estivesse passando o FrameLayoutpara o, fragmentTransaction.replace()mas eu tive o problema exato. estava mostrando o segundo fragmento em cima do anterior.

O problema foi corrigido removendo o fragmento do xml e mostrando-o programaticamente no onCreate()método da atividade do contêiner para a visualização padrão no início do programa assim:

    fragmentTransaction = getFragmentManager().beginTransaction();
    fragmentTransaction.replace(R.id.fragment_frame_layout,new ShopFragment());
    fragmentTransaction.addToBackStack(null);
    fragmentTransaction.commit();

e o xml de atividade do contêiner:

<FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
Emad
fonte
4

Você pode limpar backStack antes de substituir fragmentos:

    FragmentManager fm = getActivity().getSupportFragmentManager();

    for (int i = 0; i < fm.getBackStackEntryCount(); i++) {
        fm.popBackStack();
    }

    // replace your fragments
Michał Z.
fonte
o problema é que ele declarou o fragmento em seu arquivo de layout xml. Portanto, ele não pode ser removido / substituído em tempo de execução.
Poonam Anthony
isso funcionou para mim, tentar substituir um fragmento sem limpar a pilha parecia deixar a entrada da pilha mais recente por cima de qualquer outro fragmento.
speedynomads
3
<FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:windowBackground">
//Add fragment here
</FrameLayout>

Adicione android:background="?android:windowBackground">ao recipiente em que reside o seu fragmento. No meu caso, adicionei um FrameLayout, isso deve ajudar.

ralph tashinga nyoni
fonte
1

Use um contêiner em vez de fragmento

<FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello World!" />

Agora em MainActivity

if(condition)
    getFragmentManager().beginTransaction().replace(R.id.container,new FirstFragment()).commit();                    
else
    getFragmentManager().beginTransaction().replace(R.id.container, new SecondFragment()).commit();

Observe que sua classe de fragmento deve importar 'android.app.Fragment'. Certifique-se de usar "support.v4" ou as implementações "originais" e não as misture. Eu estava tendo esse problema porque os mixei.

Vikash Kumar Verma
fonte
0

Eu concordo com a resposta de Sapan Diwakar. Mas eu encontrei uma solução alternativa para fazer isso.

Primeiro, em sua atividade (por exemplo activity_main), onde você tem todos os layouts, adicione a FrameLayout. Sua altura e largura devem ser match parent. Além disso, dê um id.

Agora, em seu fragmento que vai substituir o layout atual, chame onPause()e onResume(). Inicialize todos os recipientes internos em View. E defina seus visibilitypara GONEdentroonResume() e para VISIBLEdentroonPause() .

NOTA : Não o FrameLayoutque você está substituindo com este fragmento.

Suponha que você tenha ViewPager, TabLayout, ImageViewe um costume <fragment>no activity_main.xml. Adicione, a FrameLayoutconforme mencionado acima.

Em abcFragment.java, em onClick()função, adicione addToBackstack(null)em transaction.

Código de exemplo:

em xyzFragment, que vai substituir abcFragment (e tudo mostrado em activity_main.xml), faça isso

@Override
    public void onResume() {
        super.onResume();

    // On resume, make everything in activity_main invisible except this fragment.
    slidingTabs = getActivity().findViewById(R.id.sliding_tabs);
    viewPager = getActivity().findViewById(R.id.pager);
    miniPlayerFragment = getActivity().findViewById(R.id.mini_pager);

    slidingTabs.setVisibility(View.GONE);
    viewPager.setVisibility(View.GONE);
    miniPlayerFragment.setVisibility(View.GONE);
}

@Override
public void onPause() {
    super.onPause();

    // Make everything visible again
    slidingTabs = getActivity().findViewById(R.id.sliding_tabs);
    viewPager = getActivity().findViewById(R.id.pager);
    miniPlayerFragment = getActivity().findViewById(R.id.mini_pager);

    slidingTabs.setVisibility(View.VISIBLE);
    viewPager.setVisibility(View.VISIBLE);
    miniPlayerFragment.setVisibility(View.VISIBLE);
}

Boa codificação!

TheOnlyAnil
fonte
0

Você pode usar o método setTransition de FragmentTransaction para corrigir o problema de sobreposição.

transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
Lavakush
fonte
0

Em Oncreate ()

  BaseFragmentloginpage fragment = new BaseFragmentloginpage();
            android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.frame, fragment);
            fragmentTransaction.isAddToBackStackAllowed();
            fragmentTransaction.commit();

agora, este será sempre o seu fragmento padrão ... se você adicionar o fragmento no layout xml, ele sempre se sobreporá, então defina o conteúdo inicial com o fragmento em tempo de execução

Volverine
fonte
0

eu tive o mesmo problema depois de usar este problema resolvido

  1. Pegue o layout do quadro onde você está substituindo seu fragmento

    <FrameLayout
                    android:id="@+id/fragment_place"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
  2. e código para substituição

    public void selectFrag(View view) {
    Fragment fr;
    
      if(view == findViewById(R.id.button2))
    {
         fr = new FragmentTwo();
    
     }else {
         fr = new FragmentOne();
     }
     FragmentManager fm = getFragmentManager();
     FragmentTransaction fragmentTransaction = fm.beginTransaction();
     fragmentTransaction.replace(R.id.fragment_place, fr);
     fragmentTransaction.commit();

Se você quiser um exemplo completo, vou enviar-lhe apenas um comentário ...

Sunil
fonte
0

Eu também tive o mesmo problema, mas foi porque eu não alterei a cor de fundo do fragmento que estava tentando adicionar ao meu layout de moldura.

Tente fazer isso, com layout_heighte layout_widthdefinido paramatch_parent

Swastik Udupa
fonte
0

Uma vez eu tive esse problema e descobri que era porque eu havia excluído acidentalmente o android:backgroundatributo que está faltando no seu código xml. Acredito que funcione como quando você está pintando uma parede, android:backgroundé a cor que a parede vai ficar e as outras vistas são colocadas em cima dessa cor base. Quando você não pinta a parede antes de posicionar suas vistas, elas estarão em cima do que já estava naquela parede, no seu caso, seu outro fragmento. Não sei se isso vai te ajudar, boa sorte.

Miguel Pinheiro
fonte
0

Tentei acima de tudo o caso e tentei consertar o problema, mas ainda não consegui solução. Eu não sei por que não está funcionando para mim. Eu concordo com as respostas acima porque muitos concordam com isso.

Estou apenas estendendo a resposta e abaixo está o caminho que está funcionando para mim.

Eu adicionei esta propriedade android:clickable="true"no layout pai superior do fragment.xmlarquivo.

Espero que alguém consiga ajuda.

Shailesh
fonte
0

Obrigado a Sapan Diwakar e outros. Essa resposta me ajudou. Eu simplesmente criei um RelativeLayout sem um fragmento dentro dele, usei o RelativeLayout como uma visão pai ou de grupo, especifiquei essa visão de grupo na transação a ser substituída e funcionou.

Código:

getSupportFragmentManager().beginTransaction()
                            .replace(R.id.content_group_view, itemDetailFragment).commit();

XML:

 <RelativeLayout
         android:id="@+id/content_group_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent">

 </RelativeLayout>
Craig D
fonte
0

Verifique seu ID de layout de quadro e substitua-o como abaixo

fragmentTransactionChange = MainActivity.this.getSupportFragmentManager().beginTransaction();
fragmentTransactionChange.replace(R.id.progileframe, changeFragment);
fragmentTransactionChange.addToBackStack(null);
fragmentTransactionChange.commit();
Sandeep Pareek
fonte