Показати приховати фрагмент в android


99

Я розробляю додаток, яке містить 2 фрагменти, і я хочу показати сховати відповідно до своїх потреб. Наступний код має простий приклад моєї проблеми. Ця проста фрагментаційність містить 1 кнопку та один фрагмент списку.

Цей простий приклад працює бездоганно. але я не задоволений фрагментом show hide. Якщо видалити layout.setVisibility (View.GONE); з коду потім ft.hide (f); не буде приховувати фрагмент. Насправді ми не приховуємо фрагмент, а приховуємо контейнер.

Моє запитання: чи це спосіб показати приховані фрагменти? Якщо ні, то поясніть на перевіреному прикладі Як приховати та показати фрагменти, оскільки багато людей стикаються з цією проблемою.

 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

1
Я припускаю, що ви намагаєтеся щоразу показувати / приховувати різні екземпляри фрагментів. Коли ви додаєте свій фрагмент (до речі, я не бачу цей фрагмент коду), додайте його за допомогою тегу, а потім отримайте за цим тегом (замість того, щоб намагатися зберегти посилання на нього). Це може бути те, чого вам не вистачає.
— Андрій Черненко

Відповіді:


159

Не возитися з прапорцями видимості контейнера - FragmentTransaction.hide / show робить це внутрішньо для вас.

Тож правильний спосіб зробити це:

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

АБО якщо ви використовуєте android.support.v4.app.Fragment

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

5
Чому ви рекомендуєте не возитися з прапорами прямо? (Я не оскаржую вашу рекомендацію, просто намагаюся її зрозуміти.)
— Еллен Спертус

1
Так, я прочитав це у вашому оригінальному повідомленні. Я сподівався, що ви можете додати обґрунтування додаткових накладних витрат. Тим часом я виявив деякі, наприклад, можливість додавання до заднього стеку.
— Еллен Спертус

2
Це схильне до помилок, оскільки ви можете змінювати свої прапори на api низького рівня та api високого рівня, і якщо ви не будете обережні (тобто прапори не синхронізуються), ви можете переслідувати дивні помилки. Ось чому рекомендується використовувати менеджер фрагментів, щоб приховати та показати ваші фрагменти.
— numan salati

@numansalati Привіт, чи існує версія сумісності (з бібліотеки підтримки) android.R.animator.fade_inта android.R.animator.fade_out?
— Заспокоєння

1
За допомогою контейнера ви можете встановити для нього ПОКАЗАТИ, ПРИКРИТИ або ВІДХОДИТИ. Немає опції GONE при приховуванні фрагмента.
— Stealth Rabbi

57

Крім того, ви можете зробити у фрагменті (наприклад, коли не вдалося отримати дані сервера):

 getView().setVisibility(View.GONE);

11
Фрагмент є дочірнім об'єктом, а не перегляду, тому не можна викликати: fragment.setVisibility (View.INVISIBLE);
— AndroidGeek

8
Аріа пропонує щось інше, пропонує отримати вигляд з цього фрагмента і зменшити його видимість.
— AlvaroSantisteban

10
getView()Може бути обережним, nullколи він ще не ініціалізований.
— TWiStErRob

22

Привіт, ви робите це, використовуючи цей підхід, усі фрагменти залишатимуться в контейнері, як тільки вони будуть додані спочатку, а потім ми просто виявляємо потрібний фрагмент і приховуємо інші в контейнері.

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

Для отримання додаткової інформації див. Https://github.com/codepath/android_guides/wiki/Creating-and-Using-Fragments . Сподіваюся, я комусь допоможу. Навіть якщо це старе питання.


1
тож ви повинні мати ще два методи, такі як displayFragmentB () та displayFragmentC ()?
— temirbek

так @temirbek, ви можете просто простежити, як реалізований метод displayFragmentA ().
— mangu23

1
Якщо у вас багато фрагментів в одній діяльності (2 або більше) і ви використовуєте метод вище, будь ласка, скористайтеся цим . Буде легше писати і читати.
— Максим Клод

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

1
правильним є ft.setCustomAnimations (android.R.anim.fade_in, android.R.anim.fade_out);
— Webserveis

8

Спробуйте це:

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

2

З мого коду, порівняно з наведеним вище рішенням, найпростішим способом є визначення макета, який містить фрагмент, тоді ви можете приховати або показати фрагмент, керуючи атрибутом макета, який вирівнюється із загальним способом перегляду. У цьому випадку додатковий код не потрібен, а додаткові атрибути розгортання фрагмента не можуть бути переміщені у зовнішній макет.

<LinearLayout style="@style/StHorizontalLinearView"
    >

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

</LinearLayout>

0

Це спрацювало для мене

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

0

відповіді тут правильні, і мені сподобалась ідея @Jyo Whiff про реалізацію шоу та приховування фрагментів, за винятком того, як він має його на даний момент, приховав би фрагмент під час першого запуску, тому я додав невелику зміну, додавши перевірку та показ isAdded фрагмент, якщо його ще немає

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

0
final Fragment fragment1 = new fragment1();
final Fragment fragment2 = new fragment2();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;

У onCreate після setContentView я сховав два фрагменти та передав їх менеджеру фрагментів, але не приховав перший фрагмент, який буде служити домом.

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

Посилання: https://medium.com/@oluwabukunmi.aluko/bottom-navigation-view-with-fragments-a074bfd08711


0

Можливо, я занадто пізно, але це може допомогти комусь у майбутньому.
Ця відповідь є модифікацією для mangu23 відповіді.
Я лише додав цикл for, щоб уникнути повторення та легко додати більше фрагментів без шаблонного коду.

Спочатку нам потрібен список фрагментів, які слід відобразити

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

Потім нам потрібно заповнити його своїми фрагментами

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

І нам потрібен спосіб дізнатись, який фрагмент було вибрано зі списку, тому нам потрібна getFragmentIndexфункція

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

І нарешті, displayFragmentметод сподобається такий:

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

Таким чином, ми можемо зателефонувати, displayFragment(homeFragment)наприклад.
Це автоматично покаже HomeFragmentта приховає будь-який інший фрагмент у списку.
Це рішення дозволяє додавати до фрагментів більше фрагментів fragmentListбез повторення ifтверджень у старій displayFragmentверсії.
Сподіваюсь, комусь це стане в нагоді.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.