Android: проблема с перекрытием фрагментов

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

public class FragmentManage extends Fragment implements ActionBar.TabListener {

    private Fragment mFragment;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
            Bundle savedInstanceState) {

        View v = inflater.inflate(R.layout.fragment_manage, container, false);

        OnClickListener clickListener = new OnClickListener() { 
            public void onClick(View v) {
                FragmentTransaction ft = getFragmentManager().beginTransaction();
                switch(v.getId()) {
                    case R.id.imageBtnCategory:
                        if (mFragment == null){
                            mFragment = new FragmentCategory();
                        }
                        ft.replace(android.R.id.content, mFragment);
                        break;
                    case R.id.imageBtnManageKey:
                        if (mFragment == null){
                            mFragment = new FragmentKeys();
                        }
                        ft.replace(android.R.id.content, mFragment);
                        break;
                    case R.id.imageBtnChangePswd:
                        if (mFragment == null){
                            mFragment = new FragmentChangePwd();
                        }
                        ft.replace(android.R.id.content, mFragment);
                        break;
                }
                ft.commit();
             }
        };

        ImageButton imageBtnCategory = (ImageButton) v.findViewById(R.id.imageBtnCategory);
        ImageButton imageBtnManageKey = (ImageButton) v.findViewById(R.id.imageBtnManageKey);
        ImageButton imageBtnChangePswd = (ImageButton) v.findViewById(R.id.imageBtnChangePswd);

        imageBtnCategory.setOnClickListener(clickListener);
        imageBtnManageKey.setOnClickListener(clickListener);
        imageBtnChangePswd.setOnClickListener(clickListener);

        return v;
    }

    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        mFragment = new FragmentManage();
        ft.add(android.R.id.content, mFragment);
        ft.attach(mFragment);
    }

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        ft.remove(mFragment);
    }

    public void onTabReselected(Tab tab, FragmentTransaction ft) {

    }
}

person girishawate    schedule 16.08.2013    source источник


Ответы (15)


Просто установите цвет фона для вашего <fragment /> в файле XML.

Решает проблему.

person kvh    schedule 16.08.2013
comment
Я новичок в разработке для Android, можете ли вы сообщить мне, как мне это сделать? - person girishawate; 16.08.2013
comment
ваш фрагмент использует макет в качестве своего вида? поэтому установите фон для макета. - person kvh; 16.08.2013
comment
Вы также можете столкнуться с проблемами, когда фрагмент позади вашего нового фрагмента все еще доступен для кликов. Если это произойдет, просто сделайте родительское представление нового фрагмента кликабельным :) - person Joe Birch; 06.12.2013
comment
А что, если кто-то хочет сохранить фон активности? - person Manos; 24.02.2015
comment
@JoeBirch У меня именно такая проблема, можете ли вы предоставить способ сделать родительское представление нового фрагмента кликабельным, потому что я не могу этого сделать. Спасибо - person shkschneider; 09.06.2015
comment
@shkschneider вы пытались установить атрибут xml android:clickable=true? - person Joe Birch; 09.06.2015
comment
Да, но в обоих XML-файлах, потому что это шаблон NavigationDrawer, поэтому я не знаю, какой фрагмент следует за каким. оттуда ничего не решает.. - person shkschneider; 09.06.2015
comment
Ваше решение сработало. Это такая глупость. У каждого макета должен быть правильный фон по умолчанию? Может ли кто-нибудь объяснить, почему он перекрывается без цвета фона? - person swapyonubuntu; 16.10.2015
comment
Это не очень хорошее решение, это всего лишь обходной путь для маскировки возможного запаха кода. - person Bevor; 18.12.2016
comment
У меня около 50 фрагментов, и все они наследуют цвет фона из пользовательского стиля. Итак, теперь мне нужно применить цвет фона к каждому фрагменту? - person Jay Donga; 28.12.2016
comment
Я пробовал это, и это работает, но это обходной путь. Есть ли лучшее решение для этого? - person jlively; 18.01.2017
comment
Работает отлично! Люблю вас ребята - person UserK; 27.01.2017
comment
Этот ответ не решит проблему. Он просто скрывает второй фрагмент. Проблема вызвана инженерными разработками, скрытыми за методом replace. - person ichalos; 29.01.2017
comment
ты гений!! - person 最白目; 16.02.2017
comment
Я использую фреймворк. - person Ahamadullah Saikat; 05.11.2017
comment
это не решение. Это всего лишь белая маска над другим фрагментом. - person huu duy; 09.03.2018
comment
Это на самом деле скрывает просмотры. Представления во фрагментах сзади по-прежнему получают события касания. - person Pawan; 23.03.2018

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

Решением будет удаление всех представлений из макета фрейма перед добавлением любого нового фрагмента.

private void changeFragment(Fragment fr){
    FrameLayout fl = (FrameLayout) findViewById(R.id.mainframe);
    fl.removeAllViews();
    FragmentTransaction transaction1 = getSupportFragmentManager().beginTransaction();
    transaction1.add(R.id.mainframe, fr);
    transaction1.commit();
}
person Sufiyan Ansari    schedule 30.10.2016
comment
У меня была проблема, когда при определенных сценариях фрагменты перекрывались (например, коснитесь чего-нибудь, чтобы загрузить новый фрагмент, затем быстро нажмите кнопку «Домой». Теперь снова откройте приложение, и загруженный фрагмент плюс предыдущий будут перекрываться). Вызов метода removeAllViews(); метод макета, в который я добавлял фрагмент, каждый раз исправлял эту проблему. Спасибо! - person sam9046; 20.11.2017
comment
ты спас мой день - person Molly; 05.07.2018
comment
это должен быть принятый ответ. Но что, если вы хотите вернуться к предыдущей активности, как можно вернуть все просмотры? - person kelvin andre; 17.09.2019
comment
Что делать, если я хочу, чтобы мой предыдущий фрагмент в бэкстеке избегал воссоздания? - person pandey_shubahm; 24.05.2020
comment
@pandey_shubham Вероятно, вы можете сделать это stackoverflow.com/a/54105721/3443247 для получения стека фрагментов. - person Sufiyan Ansari; 26.05.2020

Я могу очень поздно ответить на этот вопрос.

Примечание.

Этот ответ может не иметь отношения к вышеуказанному вопросу, но надеюсь, что он поможет некоторым.

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

Недавно я столкнулся с той же проблемой в ящике навигации. По ошибке я использовал «import android.support.v4.app.Fragment;» в одном фрагменте и использовал «import android.app.Fragment;» в нескольких других. фрагмент.

Надеюсь, это поможет кому-то..

person Roshan    schedule 18.05.2015
comment
Это была проблема в моем случае. Мне также пришлось заменить вызовы getFragmentManager на getSupportFragmentManager. - person martintama; 01.06.2015
comment
это было решением, но в случае androidx это беспомощно - person sachinmaharjan; 19.07.2019

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

  fragmentManager.popBackStack(); 

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

person Syed Raza Mehdi    schedule 11.08.2014
comment
Можете ли вы объяснить больше о том, когда и где вы бы использовали это? - person Micro; 23.03.2016
comment
@MicroR зависит от вашей ситуации, вы можете использовать его либо в onPause(), либо в onDestroyView() - person Syed Raza Mehdi; 01.04.2016

Вот как я это исправил..

Установка фона удалит эффект перекрытия с экрана, только если макет соответствует заполнению экрана.

Новые фрагменты, заменяемые при нажатии кнопки, не заменялись в tab_selected или в действии смены вкладки.

следующий код исправил это для меня

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
    // This is required since button click replaces fragment whose link is lost hence overlapping isuee was occuring
    ft.replace(android.R.id.content, mFragment); 
    // On Tab Change remove old fragment views
    ft.remove(mFragment);
}
person girishawate    schedule 06.12.2013
comment
это работает с вкладками tabhost? Если это так, я немного смущен тем, как это реализовать. - person Mike; 21.04.2014
comment
вы сначала заменяете, а затем удаляете, не думаете ли вы, что он удалит последний добавленный фрагмент... - person seema; 24.04.2014

Другая проблема может быть связана с использованием android.R.id.content в качестве контейнера. Я только что создал FrameLayout и использую идентификатор оттуда.

person irudyak    schedule 25.08.2015

Я также столкнулся с проблемой перекрытия фрагментов. Вот как я ее решил:

1) Нам нужно добавить первый фрагмент с помощью addToBackStack, чтобы он сохранился в стеке —

FirstFragment firstFragment = new FirstFragment();
getFragmentManager().beginTransaction().add(R.id.fragment_container, firstFragment).addToBackStack("first frag").commit();

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

SecondFragment secondFragment= new SecondFragment();
getFragmentManager().beginTransaction().replace(R.id.fragment_container, secondFragment).addToBackStack("second frag").commit();

3) Вот как можно обрабатывать обратное нажатие, ниже код должен присутствовать в родительском действии -

 public void onBackPressed(){
    if(getFragmentManager().getBackStackEntryCount() <= 1){
       super.onBackPressed();
    } else {
       getFragmentManager().popBackStack();
    }
 }
person Sunita    schedule 26.05.2016

Вы проверили свой XML и увидели, является ли основной макет Frame Layout? Если нет, используйте макет кадра. Это решит проблему перекрытия. Это единственный способ исправить. Я попробовал «принятый» ответ при поиске решения этой проблемы, и это не сработало.

person David Dimalanta    schedule 09.01.2019
comment
это работает для меня, спасибо. Новый фрагмент был ConstraintLayout по умолчанию при создании. Я должен изменить его на FrameLayout, тогда они больше не перекрываются. - person andre_northwind; 21.04.2020

когда у вас есть перекрывающийся фрагмент, возможно, ваш фон вашего фрагмента прозрачен, вам нужно поместить android:background="@color/white"' внутри ваших свойств фрагмента

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"

и белый нужно поместить внутрь colors.xml #FFFFFF в оставшейся папке.

person Vladimir Rockdríguez Martinez    schedule 22.09.2016

У меня иногда такая же проблема, но моя проблема не связана с разными менеджерами фрагментов (getSupportFragmentManager(), getFragmentManager()). Я думаю, что есть еще одна проблема. В моем случае, когда я открываю панель навигации, я всегда удаляю старые фрагменты в каждом пункте меню, например:

Fragment calendarFragment = context.getSupportFragmentManager().findFragmentByTag(FragmentTag.CALENDAR.name());
if (calendarFragment != null)
{
    context.getSupportFragmentManager().beginTransaction().remove(calendarFragment).commit();
}

Невозможно попасть в подменю без навигационного ящика, поэтому фрагменты в основном всегда удаляются. В некоторых случаях после того, как я удаляю и снова добавляю фрагмент внутри действия, он внезапно перекрывается другим (предыдущим) фрагментом?! Но почему диспетчер фрагментов вдруг находит предыдущие фрагменты? Это может означать, что менеджер фрагментов глючит и не удаляет старые фрагменты, или что-то другое не работает.
Я думаю, что это какая-то ошибка Android Studio или любого другого инструмента разработки adb, который используется Это. Почему я так думаю, потому что Android Studio иногда теряет экземпляр работающего приложения. Вероятно, эта проблема как-то связана с той же проблемой: Android Studio не развертывает изменения в приложении . Я еще не понял, когда это произойдет. Что я знаю, так это то, что это не может быть проблемой программирования, потому что это невозможно воспроизвести после того, как я перезапустил приложение с помощью Android Studio. Я предполагаю, что каким-то образом зависают какие-либо фоновые процессы, которые вызывают несколько экземпляров Activity, Fragments, менеджеров фрагментов и так далее. Более того, это не только этот баг. В прошлом я видел много странного поведения, похожего на это. (Например, поведение внезапно исчезло, когда приложение не было запущено IDE).

person Bevor    schedule 18.12.2016

Создание белого цвета фона тоже решило эту проблему для меня. Я думаю, что это ошибка или проблема реализации в диспетчере фрагментации Android. Я правильно реализовал замену и popBackStack().

person daniekpo    schedule 21.11.2017

Когда у меня возникла такая проблема, оказалось, что я добавляю один фрагмент с помощью childFragmentManager, а другой — с помощью родительского fragmentManager, поэтому убедитесь, что вы используете тот же тип диспетчера фрагментов.

person Olga Sokol    schedule 12.02.2018

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

backstack выглядит так и думает, что вы на frag 4 1-> 2, 2-> 3, 3-> 4, но на самом деле вы по какой-то причине на frag 6, поэтому popbackstack идет

удалить (4) добавить (3) ‹- теперь у вас есть 3 (новые) и 6 (оставшиеся), смешанные вместе

Чтобы лучше контролировать свою навигацию, я отслеживаю свои текущие/предыдущие фрагменты и заменяю их следующим образом. Это позволяет моему приложению управлять навигацией по фрагментам.

if ( !(currentFragment instanceof Settings)) {
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.fragment_container, settings);
        fragmentTransaction.addToBackStack(null);
        previousFrag = currentFragment;
        currentFragment = settings;
        fragmentTransaction.commit();
    }

Во-вторых, я считаю, что метод fragmentmanager.replace() является лучшей альтернативой. Не уверен, что это доступно для OP в то время.

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

фрагментТранзакция.addToBackStack(null);

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

Не уверен, что это считается хорошим решением, но оно работает очень хорошо.

1- получить счетчик обратного стека 2- удалить все существующие фрагменты 3- отслеживать объекты фрагментов 4- если это последний фрагмент в стеке, пользователь хочет выйти, и поскольку мы добавили основное действие в задний стек, нам нужно дважды поп

@Override
public void onBackPressed() {

int num = getFragmentManager().getBackStackEntryCount();


        fl.removeAllViews();
        super.onBackPressed();

        if  (currentFragment != previousFrag) {
            currentFragment = previousFrag;
        }else{
            currentFragment = null;
        }

        if (num == 1){
           super.onBackPressed();
        }
person cagney    schedule 05.06.2018

Я нашел простое и чистое решение. Для меня проблема заключалась в выполнении транзакции фрагмента при каждом вызове onCreate() моей Activity. Теперь я выполняю транзакцию, только если saveInstanceState == null

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        if (savedInstanceState == null) {
        // replace fragment 
        }
    }
person Ivan Syabro    schedule 14.06.2018

Вместо использования фрагмента в качестве контейнера для фрагментов используйте FragmentContainerView. Это решило проблему для меня

person Crucialjun    schedule 16.06.2020