Pokaż ukryty fragment w systemie Android

100

Tworzę aplikację, która zawiera 2 fragmenty i chcę pokazać hide w zależności od potrzeb. Poniższy kod zawiera prosty przykład mojego problemu. Ta prosta aktywność fragmentaryczna zawiera 1 przycisk i jeden fragment listy.

Ten prosty przykład działa bez zarzutu. ale nie jestem zadowolony z fragmentu show hide. Jeśli usuniesz layout.setVisibility (View.GONE); z kodu, a następnie ft.hide (f); nie ukryje fragmentu. W rzeczywistości nie ukrywamy fragmentu, który ukrywamy kontener.

Moje pytanie brzmi: czy to jest sposób na pokazanie ukrytych fragmentów? Jeśli nie, wyjaśnij za pomocą testowanego przykładu Jak ukryć i pokazać fragmenty, ponieważ wiele osób boryka się z tym problemem.

 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
źródło
Dlaczego musisz ustawić widoczność kontenera? Powinien działać bez ustawiania widoczności.
Andrii Chernenko
Dokładnie powinien działać bez widoczności pojemnika, ale nie działa. Proszę, podziel się ze mną prostym przykładem działania. Wtedy wiedziałbym, gdzie brakuje mi.
abidkhan303
1
Domyślam się, że za każdym razem próbujesz pokazać / ukryć inną instancję fragmentu. Kiedy dodajesz swój fragment (swoją drogą nie widzę tego fragmentu kodu) dodaj go za pomocą tagu, a następnie pobieraj go za pomocą tego tagu (zamiast próbować przechowywać odniesienie do niego). To może być to, czego Ci brakuje.
Andrii Chernenko

Odpowiedzi:

159

Nie zadzieraj z flagami widoczności kontenera - FragmentTransaction.hide / show robi to wewnętrznie za Ciebie.

Zatem prawidłowy sposób na zrobienie tego to:

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

LUB jeśli używasz 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
źródło
5
Dlaczego odradzasz bezpośrednie manipulowanie flagami? (Nie kwestionuję twojej rekomendacji, po prostu próbuję to zrozumieć.)
Ellen Spertus,
1
Tak, przeczytałem to w twojej oryginalnej wiadomości. Miałem nadzieję, że możesz uzasadnić dodatkowe koszty. W międzyczasie odkryłem kilka, na przykład opcję dodawania do tylnego stosu.
Ellen Spertus,
2
Jest to podatne na błędy, ponieważ możesz zmienić flagi na niskim poziomie i wysokim poziomie, a jeśli nie jesteś ostrożny (np. Flagi tracą synchronizację), możesz ścigać dziwne błędy. Dlatego zaleca się używanie menedżera fragmentów do ukrywania i pokazywania swoich fragmentów.
numan salati
@numansalati Cześć, czy jest jakaś zgodna (z biblioteki wsparcia) wersja android.R.animator.fade_ini android.R.animator.fade_out?
Solace
1
Za pomocą kontenera możesz ustawić go na POKAŻ, UKRYJ lub NIE MA. Nie ma opcji GONE podczas ukrywania fragmentu.
Stealth Rabbi
58

Dodatkowo możesz zrobić we fragmencie (na przykład gdy nie udało się pobrać danych z serwera):

 getView().setVisibility(View.GONE);
Aria
źródło
11
Fragment jest dzieckiem Object, a nie View, więc nie można wywołać: fragment.setVisibility (View.INVISIBLE);
AndroidGeek,
8
Arià proponuje coś innego, sugeruje wyciągnięcie widoku z tego fragmentu i odstawienie jego widoczności.
AlvaroSantisteban
10
Ostrożnie getView()może być, nullgdy nie jest jeszcze zainicjowany.
TWiStErRob
23

Cześć, robisz to używając tego podejścia, wszystkie fragmenty pozostaną w kontenerze po ich wstępnym dodaniu, a następnie po prostu odsłaniamy żądany fragment i ukrywamy pozostałe w kontenerze.

// 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();
}

Więcej informacji można znaleźć na https://github.com/codepath/android_guides/wiki/Creating-and-Using-Fragments . Mam nadzieję, że komukolwiek pomogę. Nawet jeśli jest to stare pytanie.

mangu23
źródło
1
więc musisz mieć jeszcze dwie metody, takie jak displayFragmentB () i displayFragmentC ()?
temirbek
tak @temirbek, możesz po prostu śledzić sposób implementacji metody displayFragmentA ().
mangu23
1
Jeśli masz wiele fragmentów w jednym ćwiczeniu (2 lub więcej) i korzystasz z powyższej metody, użyj tego . Łatwiej będzie pisać i czytać.
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 the Whiff
źródło
1
poprawna to ft.setCustomAnimations (android.R.anim.fade_in, android.R.anim.fade_out);
Webserveis
8

Spróbuj tego:

MapFragment mapFragment = (MapFragment)getFragmentManager().findFragmentById(R.id.mapview);
mapFragment.getView().setVisibility(View.GONE);
Ingo
źródło
2

Z mojego kodu, w porównaniu do powyższego rozwiązania, najprościej jest zdefiniować układ, który zawiera fragment, a następnie można ukryć lub odkryć ten fragment, kontrolując atrybut układu, który jest zgodny z ogólnym sposobem widoku. W tym przypadku nie jest potrzebny żaden dodatkowy kod, a dodatkowe atrybuty wdrożenia fragmentu można przenieść do układu zewnętrznego.

<LinearLayout style="@style/StHorizontalLinearView"
    >

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

</LinearLayout>
BrainAtom
źródło
0

To zadziałało dla mnie

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
źródło
0

odpowiedzi tutaj są poprawne i podobał mi się pomysł na @Jyo Whiff dotyczący implementacji fragmentów pokazujących i ukrywających, z wyjątkiem tego, że sposób, w jaki obecnie ma, ukrywałby fragment przy pierwszym uruchomieniu, więc dodałem niewielką zmianę, dodając isAdded check and show fragment, jeśli jeszcze nie jest

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
źródło
0
final Fragment fragment1 = new fragment1();
final Fragment fragment2 = new fragment2();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;

W onCreate, po setContentView, ukryłem dwa fragmenty i przekazałem je do menedżera fragmentów, ale nie ukryłem pierwszego fragmentu, który będzie służył jako dom.

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

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

Rachit Vohera
źródło
0

Może jestem o wiele za późno, ale może to komuś pomóc w przyszłości.
Ta odpowiedź jest modyfikacją mangu23 odpowiedzi
Dodałem tylko pętlę for, aby uniknąć powtórzeń i łatwo dodać więcej fragmentów bez standardowego kodu.

Najpierw potrzebujemy listy fragmentów, które mają zostać wyświetlone

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

Następnie musimy wypełnić go naszymi fragmentami

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

Potrzebujemy sposobu, aby wiedzieć, który fragment został wybrany z listy, więc potrzebujemy getFragmentIndexfunkcji

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

I wreszcie displayFragmentmetoda będzie wyglądać tak:

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

W ten sposób możemy displayFragment(homeFragment)na przykład zadzwonić .
Spowoduje to automatyczne wyświetlenie HomeFragmenti ukrycie dowolnego innego fragmentu na liście.
Takie rozwiązanie pozwala na dołączanie większej liczby fragmentów do pliku fragmentListbez konieczności powtarzania ifinstrukcji ze starej displayFragmentwersji.
Mam nadzieję, że komuś to się przyda.

Mohamed Medhat
źródło