Фрагмент не заменяется, а кладется поверх предыдущего

105

Деятельность:

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

Код в представлении:

<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" /> 

Проблема в том, что на самом деле контент не заменяется - он помещается сверху (поэтому он перекрывается).

Когда я нажимаю кнопку "Назад", первый фрагмент отображается правильно (без второго), но изначально оба видны (я хочу, чтобы был виден только последний).

Что мне здесь не хватает?

Инструмент
источник
В моем случае проблема была связана с тем, что я не использовал соответствующий идентификатор представления контейнера, т.е. я не передавал правильный containerViewIdreplaceметоде).
nbro

Ответы:

145

Здесь вы делаете две ошибки:

  1. Вы не можете заменить фрагмент, который статически помещен в xmlфайл макета. Вы должны создать контейнер (например, a FrameLayout) в макете, а затем программно добавить фрагмент, используя FragmentTransaction.

  2. FragmentTransaction.replaceожидает идентификатор контейнера, который содержит фрагмент, а не идентификатор фрагмента в качестве первого параметра. Таким образом, вы должны передать первый аргумент в качестве идентификатора контейнера, в который вы добавили первый фрагмент.

Вы можете обратиться к этой ссылке для получения более подробной информации.

Сапан Дивакар
источник
17
FrameLayoutЛучше использовать в качестве контейнера, чем использовать LinearLayout.
Марсель Бро
3
Использование пустого FrameLayout в Activity решило и мою проблему
Subtle Fox
1
Это работает. Но затем, когда я запускаю свое приложение и сразу же нажимаю кнопку «Назад», я попадаю в состояние, в котором фрагмент пуст, вместо того, чтобы выйти из приложения?
MasterScrat
@MasterScrat Не указывайте addTobackStack(..)при совершении транзакции в первый раз. Это позволит избежать помещения пустого контейнера FrameLayout в задний стек. Вы по-прежнему сможете вернуться к добавляемому фрагменту.
Alex Meuer
Вот отличное видео, демонстрирующее ваше объяснение. youtube.com/watch?v=EbcdMxAIr54
SQL and Java Learner
32

У меня была аналогичная проблема, но моя проблема заключалась в том, что я использовал два разных менеджера фрагментов: один от getSupportFragmentManager()и один от getFragmentManager(). Если бы я добавил один фрагмент с помощью, SupportFragmentManagerа затем попытался заменить фрагмент на FragmentManager, фрагмент просто добавился бы поверх. Мне нужно было изменить код, чтобы использовать тот же код, FragmentManagerи это решило проблему.

swbandit
источник
17

Сайт разработчика Android предлагает использовать FrameLayoutдля динамической загрузки фрагментов во время выполнения. Вы жестко запрограммировали фрагмент в своем XML-файле. Поэтому его нельзя удалить во время выполнения, как указано в этой ссылке:

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

по этой ссылке показано, как добавлять фрагменты через вашу программу:

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

Пунам Энтони
источник
7

У меня была та же проблема, и я видел все ответы, но ни один из них не содержал моей ошибки! Прежде чем пытаться заменить текущий фрагмент, я показывал фрагмент по умолчанию в xml активности контейнера следующим образом:

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

после этого, хотя я проходил мимо FrameLayoutк , fragmentTransaction.replace()но я имел точную проблему. он показывал второй фрагмент поверх предыдущего.

Проблема устранена удалением фрагмента из xml и его программным отображением в onCreate()методе активности контейнера для предварительного просмотра по умолчанию при запуске программы следующим образом:

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

и активность контейнера xml:

<FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
Эмад
источник
4

Вы можете очистить backStack перед заменой фрагментов:

    FragmentManager fm = getActivity().getSupportFragmentManager();

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

    // replace your fragments
Михал З.
источник
проблема в том, что он объявил фрагмент в своем файле макета xml. Следовательно, его нельзя удалить / заменить во время работы.
Poonam Anthony
это сработало для меня, попытка заменить фрагмент без очистки backstack, похоже, оставила самую последнюю запись backstack поверх любого другого фрагмента.
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>

Добавьте android:background="?android:windowBackground">в контейнер, в котором находится ваш фрагмент. В моем случае я добавил FrameLayout, что должно помочь.

Ральф Ташинга Ньони
источник
1

Используйте контейнер вместо фрагмента

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

Сейчас в MainActivity

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

Обратите внимание, что ваш класс фрагмента должен импортировать 'android.app.Fragment'. Убедитесь, что вы используете «support.v4» или «оригинальные» реализации и не смешиваете их. У меня возникла эта проблема, потому что я их смешал.

Викаш Кумар Верма
источник
0

Я согласен с ответом Сапана Дивакара. Но я нашел обходной путь, как это сделать.

Во-первых, в вашей деятельности (например activity_main), где у вас есть все макеты, добавьте файл FrameLayout. Его высота и ширина должны быть match parent. Кроме того, дайте ему id.

Теперь в вашем фрагменте, который заменит текущий макет, вызовите onPause()и onResume(). Инициализируйте все внутренние контейнеры View. И установить их visibilityToGONE вonResume() и VISIBLEвonPause() .

ПРИМЕЧАНИЕ . Не тот, FrameLayoutкоторый вы заменяете этим фрагментом.

Предположим , что у вас есть ViewPager,TabLayout , ImageViewи обычай <fragment>в activity_main.xml. Добавьте, FrameLayoutкак указано выше.

В abcFragment.java , в onClick()функции, добавьте addToBackstack(null)в transaction.

Пример кода:

в xyzFragment, который заменит abcFragment (и все, что показано в activity_main.xml), сделайте это

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

Удачного кодирования!

TheOnlyAnil
источник
0

Вы можете использовать метод setTransition из FragmentTransaction, чтобы исправить проблему перекрытия.

transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
Лавакуш
источник
0

В Oncreate ()

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

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

Вольверин
источник
0

У меня была такая же проблема после решения этой проблемы

  1. Возьмите макет кадра, где вы заменяете фрагмент ur

    <FrameLayout
                    android:id="@+id/fragment_place"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
  2. и код для замены

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

Если вам нужен весь пример, я пришлю вам комментарий ...

Сунил
источник
0

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

Попробуйте сделать это с помощью layout_heightи layout_widthустановитеmatch_parent

Свастик Удупа
источник
0

Однажды у меня была эта проблема, и я обнаружил, что это произошло потому, что я случайно удалил android:backgroundатрибут, который отсутствует в вашем xml-коде. Я считаю, что это работает так, как если бы вы красили стену, android:backgroundэто цвет стены, а другие виды помещаются поверх этого основного цвета. Если вы не раскрашиваете стену до того, как разместите свои виды, они будут поверх того, что уже было в этой стене, в вашем случае, вашего другого фрагмента. Не знаю, поможет ли это вам, удачи.

Мигель Пиньейру
источник
0

Я пробовал, прежде всего, этот случай и пытаюсь решить проблему, но все еще не нашел решения. Я не знаю, почему у меня это не работает. Я согласен с приведенными выше ответами, потому что многие с ними согласны.

Я просто расширяю ответ, и ниже приведен способ, который работает для меня.

Я добавил это свойство android:clickable="true"в верхний родительский макет fragment.xmlфайла.

Надеюсь, кому-нибудь помогут.

Шайлеш
источник
0

Спасибо Сапану Дивакару и другим. Этот ответ мне помог. Я просто создал RelativeLayout без фрагмента внутри, использовал RelativeLayout в качестве родительского или группового представления, указал это групповое представление в транзакции для замены, и это сработало.

Код:

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>
Крейг Д.
источник
0

Проверьте идентификатор макета кадра и замените его, как показано ниже.

fragmentTransactionChange = MainActivity.this.getSupportFragmentManager().beginTransaction();
fragmentTransactionChange.replace(R.id.progileframe, changeFragment);
fragmentTransactionChange.addToBackStack(null);
fragmentTransactionChange.commit();
Сандип Парик
источник