Mostrar ocultar fragmento no android

98

Estou desenvolvendo um aplicativo que contém 2 fragmentos e quero mostrar hide de acordo com minha necessidade. O código a seguir tem um exemplo simples do meu problema. Esta Fragmentactivity simples contém 1 botão e um listfragment.

Este exemplo simples funciona sem falhas. mas não estou satisfeito com show hide fragmento. Se você remover layout.setVisibility (View.GONE); do código, em seguida, ft.hide (f); não vai esconder fragmento. Na verdade, não estamos escondendo fragmentos, estamos escondendo um container.

Minha pergunta é: essa é uma maneira de mostrar fragmentos ocultos? Caso contrário, explique com um exemplo testado como ocultar e mostrar fragmentos porque muitas pessoas estão enfrentando esse problema.

 public class MainActivity extends FragmentActivity implements OnClickListener {

        Fragment1 f;
        Button b;
        LinearLayout layout;
        Fragment myf;
        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            b = (Button) findViewById(R.id.button1);
            layout = (LinearLayout) findViewById(R.id.ll);
            f = new Fragment1();
        }

        @Override
        public void onClick(View v) {

            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);

            if (f.isHidden()) {
                ft.show(f);
                layout.setVisibility(View.VISIBLE);
                b.setText("Hide");
            } else {
                ft.hide(f);
                b.setText("Show");
                layout.setVisibility(View.GONE);
            }
            ft.commit();
            // TODO Auto-generated method stub
        }
abidkhan303
fonte
Por que você precisa definir a visibilidade do contêiner? Deve funcionar sem definir a visibilidade.
Andrii Chernenko
Exatamente, ele deve funcionar sem visibilidade do contêiner, mas não está funcionando. Por favor, compartilhe um exemplo simples de trabalho comigo. Então eu saberia onde estou perdendo.
abidkhan303
1
Meu palpite é que você está tentando mostrar / ocultar instâncias diferentes de fragmento a cada vez. Quando você adiciona seu fragmento (não vejo este pedaço de código, a propósito) adicione-o com tag e, em seguida, recupere-o por meio dessa tag (em vez de tentar armazenar referência a ele). Isso pode ser o que você está perdendo.
Andrii Chernenko

Respostas:

158

Não mexa com os sinalizadores de visibilidade do contêiner - FragmentTransaction.hide / show faz isso internamente para você.

Portanto, a maneira correta de fazer isso é:

FragmentManager fm = getFragmentManager();
fm.beginTransaction()
          .setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
          .show(somefrag)
          .commit();

OU se você estiver usando android.support.v4.app.Fragment

 FragmentManager fm = getSupportFragmentManager();
 fm.beginTransaction()
          .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
          .show(somefrag)
          .commit();
Numan Salati
fonte
5
Por que você não recomenda mexer nos sinalizadores diretamente? (Não estou contestando sua recomendação, apenas tentando entendê-la.)
Ellen Spertus
1
Sim, li isso na sua mensagem original. Eu esperava que você pudesse acrescentar uma justificativa para a sobrecarga extra. Nesse ínterim, descobri alguns, como a opção de adicionar à pilha posterior.
Ellen Spertus
2
É propenso a erros porque você pode alterar seus sinalizadores na API de baixo nível e na API de alto nível e se você não tiver cuidado (ou seja, os sinalizadores saem de sincronia), você pode estar perseguindo bugs estranhos. É por isso que é recomendado usar o gerenciador de fragmentos para ocultar e mostrar seus fragmentos.
numan salati
@numansalati Olá, há alguma versão de compatibilidade (da biblioteca de suporte) de android.R.animator.fade_ine android.R.animator.fade_out?
Solace
1
Com o contêiner, você pode defini-lo como MOSTRAR, OCULTAR ou SEU. Não há opção GONE ao ocultar um fragmento.
Stealth Rabbi
57

Além disso, você pode fazer em um fragmento (por exemplo, ao obter dados do servidor com falha):

 getView().setVisibility(View.GONE);
Ária
fonte
11
Fragment é filho de Object e não View, portanto, não é possível chamar: fragment.setVisibility (View.INVISIBLE);
AndroidGeek
8
Arià está sugerindo algo diferente, está sugerindo tirar a visão daquele fragmento e definir sua visibilidade para desaparecer.
AlvaroSantisteban
10
Cuidado getView()pode ser nullquando ele ainda não foi inicializado.
TWiStErRob
22

Olá, você faz isso usando esta abordagem, todos os fragmentos permanecerão no contêiner uma vez adicionados inicialmente e então estamos simplesmente revelando o fragmento desejado e escondendo os outros dentro do contêiner.

// Within an activity
private FragmentA fragmentA;
private FragmentB fragmentB;
private FragmentC fragmentC;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (savedInstanceState == null) {
        fragmentA = FragmentA.newInstance("foo");
        fragmentB = FragmentB.newInstance("bar");
        fragmentC = FragmentC.newInstance("baz");
    }
}


// Replace the switch method
protected void displayFragmentA() {
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    if (fragmentA.isAdded()) { // if the fragment is already in container
        ft.show(fragmentA);
    } else { // fragment needs to be added to frame container
        ft.add(R.id.flContainer, fragmentA, "A");
    }
    // Hide fragment B
    if (fragmentB.isAdded()) { ft.hide(fragmentB); }
    // Hide fragment C
    if (fragmentC.isAdded()) { ft.hide(fragmentC); }
    // Commit changes
    ft.commit();
}

Consulte https://github.com/codepath/android_guides/wiki/Creating-and-Using-Fragments para obter mais informações. Espero poder ajudar alguém. Mesmo que seja uma pergunta antiga.

mangu23
fonte
1
então você precisa ter mais dois métodos como displayFragmentB () e displayFragmentC ()?
temirbek
sim @temirbek você pode apenas seguir como o método displayFragmentA () é implementado.
mangu23
1
Se você tiver muitos fragmentos em uma atividade (2 ou mais) e estiver usando o método acima, use -o . Será mais fácil escrever e ler.
Maxime Claude
8
public void showHideFragment(final Fragment fragment){

    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.setCustomAnimations(android.R.animator.fade_in,
                    android.R.animator.fade_out);

    if (fragment.isHidden()) {
        ft.show(fragment);
        Log.d("hidden","Show");
    } else {
        ft.hide(fragment);
        Log.d("Shown","Hide");                        
    }

    ft.commit();
}
Jyo o Whiff
fonte
1
correto é ft.setCustomAnimations (android.R.anim.fade_in, android.R.anim.fade_out);
Webserveis
8

Experimente isto:

MapFragment mapFragment = (MapFragment)getFragmentManager().findFragmentById(R.id.mapview);
mapFragment.getView().setVisibility(View.GONE);
Ingo
fonte
2

Do meu código, comparando com a solução acima, a maneira mais simples é definir um layout que contém o fragmento, então você pode ocultar ou reexibir o fragmento controlando o atributo de layout que está alinhado com a visão geral. Nenhum código adicional necessário neste caso e os atributos de implantação adicionais do fragmento podem ser movidos para o layout externo.

<LinearLayout style="@style/StHorizontalLinearView"
    >

    <fragment
        android:layout_width="match_parent"
        android:layout_height="390dp"
        android:layout_alignParentTop="true"
        />

</LinearLayout>
BrainAtom
fonte
0

Isso funcionou para mim

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        if(tag.equalsIgnoreCase("dashboard")){

            DashboardFragment dashboardFragment = (DashboardFragment)
                    fragmentManager.findFragmentByTag("dashboard");
            if(dashboardFragment!=null) ft.show(dashboardFragment);

            ShowcaseFragment showcaseFragment = (ShowcaseFragment)
                    fragmentManager.findFragmentByTag("showcase");
            if(showcaseFragment!=null) ft.hide(showcaseFragment);

        } else if(tag.equalsIgnoreCase("showcase")){
            DashboardFragment dashboardFragment = (DashboardFragment)
                    fragmentManager.findFragmentByTag("dashboard");
            if(dashboardFragment!=null) ft.hide(dashboardFragment);

            ShowcaseFragment showcaseFragment = (ShowcaseFragment)
                    fragmentManager.findFragmentByTag("showcase");
            if(showcaseFragment!=null) ft.show(showcaseFragment);
        }

        ft.commit();
shankey
fonte
0

as respostas aqui estão corretas e eu gostei de @Jyo, a ideia de Whiff de uma implementação de mostrar e ocultar o fragmento, exceto que a forma como ele o faz atualmente esconderia o fragmento na primeira execução, então eu adicionei uma pequena mudança em que adicionei a verificação e exibição isAdded o fragmento se ainda não for

public void showHideCardPreview(int id) {
    FragmentManager fm = getSupportFragmentManager();
    Bundle b = new Bundle();
    b.putInt(Constants.CARD, id);
    cardPreviewFragment.setArguments(b);
    FragmentTransaction ft = fm.beginTransaction()
        .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
    if (!cardPreviewFragment.isAdded()){
        ft.add(R.id.full_screen_container, cardPreviewFragment);
        ft.show(cardPreviewFragment);
    } else {
        if (cardPreviewFragment.isHidden()) {
            Log.d(TAG,"++++++++++++++++++++ show");
            ft.show(cardPreviewFragment);
        } else {
            Log.d(TAG,"++++++++++++++++++++ hide");
            ft.hide(cardPreviewFragment);
        }
    }

    ft.commit();
} 
martinseal1987
fonte
0
final Fragment fragment1 = new fragment1();
final Fragment fragment2 = new fragment2();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;

Em onCreate, após setContentView, eu escondi dois fragmentos e os enviei para o gerenciador de fragmentos, mas não escondi o primeiro fragmento que servirá como home.

fm.beginTransaction().add(R.id.main_container, fragment2, "2").hide(fragment2).commit();
fm.beginTransaction().add(R.id.main_container,fragment1, "1").commit();
 @Override
    public void onClick(View v) {
        Fragment another = fragment1;
         if(active==fragment1){
          another = fragment2;
         }
            fm.beginTransaction().hide(active).show(another).commit();
            active = another;
}

Ref: https://medium.com/@oluwabukunmi.aluko/bottom-navigation-view-with-fragments-a074bfd08711

Rachit Vohera
fonte
0

Posso ser tarde demais, mas pode ajudar alguém no futuro.
Esta resposta é uma modificação paramangu23 resposta que
eu adicionei apenas um loop for para evitar a repetição e adicionar facilmente mais fragmentos sem código clichê.

Primeiro precisamos de uma lista dos fragmentos que devem ser exibidos

public class MainActivity extends AppCompatActivity{
    //...
    List<Fragment> fragmentList = new ArrayList<>();
}

Então, precisamos preenchê-lo com nossos fragmentos

@Override
protected void onCreate(Bundle savedInstanceState) {
    //...
    HomeFragment homeFragment = new HomeFragment();
    MessagesFragment messagesFragment = new MessagesFragment();
    UserFragment userFragment = new UserFragment();
    FavoriteFragment favoriteFragment = new FavoriteFragment();
    MapFragment mapFragment = new MapFragment();

    fragmentList.add(homeFragment);
    fragmentList.add(messagesFragment);
    fragmentList.add(userFragment);
    fragmentList.add(favoriteFragment);
    fragmentList.add(mapFragment);
}

E precisamos de uma maneira de saber qual fragmento foi selecionado da lista, então precisamos da getFragmentIndexfunção

private int getFragmentIndex(Fragment fragment) {
    int index = -1;
    for (int i = 0; i < fragmentList.size(); i++) {
        if (fragment.hashCode() == fragmentList.get(i).hashCode()){
            return i;
        }
    }
    return index;
}

E, finalmente, o displayFragmentmétodo será assim:

private void displayFragment(Fragment fragment) {
        int index = getFragmentIndex(fragment);
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if (fragment.isAdded()) { // if the fragment is already in container
            transaction.show(fragment);
        } else { // fragment needs to be added to frame container
            transaction.add(R.id.placeholder, fragment);
        }
        // hiding the other fragments
        for (int i = 0; i < fragmentList.size(); i++) {
            if (fragmentList.get(i).isAdded() && i != index) {
                transaction.hide(fragmentList.get(i));
            }
        }
        transaction.commit();
    }

Desta forma, podemos chamar, displayFragment(homeFragment)por exemplo.
Isso mostrará automaticamente HomeFragmente ocultará qualquer outro fragmento da lista.
Esta solução permite anexar mais fragmentos ao fragmentListsem ter que repetir as ifinstruções da displayFragmentversão anterior.
Espero que alguém ache isso útil.

Mohamed Medhat
fonte