Показать скрытый фрагмент в android


100

Я разрабатываю приложение, которое содержит 2 фрагмента, и я хочу показать скрытие в соответствии с моими потребностями. В следующем коде есть простой пример моей проблемы. Это простое действие Fragmentactivity содержит 1 кнопку и один фрагмент списка.

Этот простой пример работает безупречно. но меня не устраивает фрагмент показать скрыть. Если вы удалите 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
Я предполагаю, что вы каждый раз пытаетесь показать / скрыть разные экземпляры фрагмента. Когда вы добавляете свой фрагмент (кстати, я не вижу этот фрагмент кода), добавьте его с помощью тега, а затем извлеките его с помощью этого тега (вместо попытки сохранить ссылку на него). Это может быть то, что вам не хватает.
Андрей Черненко

Ответы:


160

Не связывайтесь с флагами видимости контейнера - 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, и если вы не будете осторожны (т.е. флаги не синхронизируются), вы можете преследовать странные ошибки. Вот почему рекомендуется использовать диспетчер фрагментов, чтобы скрыть и показать ваши фрагменты.
Нуман Салати

@numansalati Привет, есть ли совместимая (из библиотеки поддержки) версия android.R.animator.fade_inи android.R.animator.fade_out?
Solace

1
С помощью контейнера вы можете установить его на ПОКАЗАТЬ, СКРЫТЬ или УДАЛИТЬ. При скрытии фрагмента нет опции GONE.
Стелс раввин,

58

Кроме того, вы можете сделать во фрагменте (например, при сбое получения данных сервера):

 getView().setVisibility(View.GONE);

11
Фрагмент является дочерним элементом объекта, а не представления, поэтому нельзя вызывать: fragment.setVisibility (View.INVISIBLE);
AndroidGeek

8
Ария предлагает нечто иное, предлагает получить вид из этого фрагмента и отключить его видимость.
AlvaroSantisteban

10
Тщательное getView()может быть , nullкогда он еще не инициализирован.
TWiStErRob 01

23

Привет, вы делаете это, используя этот подход, все фрагменты останутся в контейнере после первоначального добавления, а затем мы просто открываем нужный фрагмент и скрываем другие внутри контейнера.

// 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 the 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.