39

I am facing a problem of overlapping fragments when i switch between tabs and attach fragments to a tab view below is my code please help

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

    }
}
galvan
  • 7,400
  • 7
  • 38
  • 55
girishawate
  • 476
  • 1
  • 5
  • 8

17 Answers17

96

Just set a background color to your <fragment /> in XML file.

Solves the issue.

shkschneider
  • 17,833
  • 13
  • 59
  • 112
kvh
  • 2,118
  • 19
  • 29
  • 2
    I am new to android development, can you let me know how do I do that ? – girishawate Aug 16 '13 at 13:49
  • your fragment use a layout as its view? so set background to the layout. – kvh Aug 16 '13 at 13:50
  • 15
    You may also come up with problems where the fragment behind your new fragment is still clickable. If this happens then just make the parent view of the new fragment clickable :) – Joe Birch Dec 06 '13 at 14:54
  • 6
    What about if one wants to keep activitie's background? – Manos Feb 24 '15 at 01:55
  • @JoeBirch I have that exact problem, can you provide a way to make "the parent view of the new fragment clickable" because I fail at doing so. Thx – shkschneider Jun 09 '15 at 09:35
  • 1
    @shkschneider have you tried setting the xml attribute android:clickable="true"? – Joe Birch Jun 09 '15 at 11:14
  • Yes, but on both XMLs because it's a NavigationDrawer pattern so I don't know what Fragment follows which one. Solves nothing from there.. – shkschneider Jun 09 '15 at 12:23
  • Your solution worked .This is such a silly thing. Every layout must be having default background right?Can anyone explain why it overlaps without background color? – swapyonubuntu Oct 16 '15 at 19:53
  • 19
    This is no good solution, just a workaround to mask possible code smell. – Bevor Dec 18 '16 at 19:03
  • I have around 50 Fragments and all of them inherit background color from custom style. So now I have to apply background colour to each and every fragment? – Jay Donga Dec 28 '16 at 15:22
  • I've tried this and it works, but it is a workaround. Is there a better solution to this? – jlively Jan 18 '17 at 14:35
  • This answer will not solve the problem. It just hides the second fragment. The problem is caused by the engineering hidden behind the replace method. – ichalos Jan 29 '17 at 18:16
  • I am using framelayout. – Ahamadullah Saikat Nov 05 '17 at 10:48
  • this is not a solution. It's only a white mask above the other fragment. – huu duy Mar 09 '18 at 11:49
  • This actually hides views. The views in the fragments in the back still receives touch events. – Pawan Mar 23 '18 at 14:50
  • If you are still here, please consider using androidx.navigation. It saves time and is easy. – Xserge May 23 '22 at 13:19
21

Well Setting up fragment background color is not a solution because fragment will be still in the activity stack which may consume memory.

Solution would be remove all views from your framelayout before adding any new fragment.

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();
}
Sufiyan Ansari
  • 1,780
  • 20
  • 22
  • 1
    I had an issue, where under certain scenarios fragments would overlap (e.g. tap something to load a new fragment then quickly press the home button. Now reopen the app and the fragment you loaded plus the previous would overlap). Calling the "removeAllViews();" method of the layout I was adding the fragment to each time fixed this issue. Thanks! – sam9046 Nov 20 '17 at 19:00
  • 1
    you saved my day – Molly Jul 05 '18 at 11:30
  • 1
    this should be the accepted answer. But what if you want to go back to previous activity how would one add all views back? – kelvin andre Sep 17 '19 at 12:34
  • What if I want my previous fragment in backstack to avoid recreation ? – pandey_shubham May 24 '20 at 00:05
  • @pandey_shubham You can probably do the this https://stackoverflow.com/a/54105721/3443247 to achieve fragment stack. – Sufiyan Ansari May 26 '20 at 09:40
16

I may be very late to answer this question.

Note:

This answer may not be related to the above question, But hope it will help for some.

Sometimes, Fragment overlap issue occurs when we try to use the different type of fragments( i.e using support fragment's in few fragments and normal fragments in someother fragment )

Recently i faced the same problem in Navigation drawer. By mistake, i used "import android.support.v4.app.Fragment;" in one fragment, And used "import android.app.Fragment;" in few other fragment.

Hope this will help for somebody..

Roshan
  • 1,380
  • 13
  • 23
10

fragment manager maintains the stack of all the previous fragments that are replaced sometimes the back stack fragments overlaps with the fragment we replaced, for me

  fragmentManager.popBackStack(); 

works, we can do this in a loop too to pop all the fragments in the stack hope it helps, Thanks. Happy Coding :)

Syed Raza Mehdi
  • 4,067
  • 1
  • 31
  • 47
5

This is how I fixed it ..

Setting the background would remove the overlapping effect from the screen only if the layout is matched to fill screen

New fragments replaced on button clicks were not getting replaced on tab_selected or tab change action

following code fixed it for me

    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);
}
girishawate
  • 476
  • 1
  • 5
  • 8
  • does this work with tabhost tabs? If so I am a little confused on how to implement it. – Mike Apr 20 '14 at 21:08
  • 3
    you are first replacing then removing, dont you think it will remove latest added fragment... – seema Apr 24 '14 at 10:28
5

I also faced fragment overlapping issue. Here is how I solved it.

  1. We need to add the first fragment with addToBackStack, so that it is retained in the stack.
    FirstFragment firstFragment = new FirstFragment();
    getFragmentManager()
        .beginTransaction()
        .add(R.id.fragment_container, firstFragment)
        .addToBackStack("first frag")
        .commit();
  1. While adding the second fragment, replace the first fragment rather than adding it. Since the first fragment was already added in the stack, so it will be present when you press back from second fragment.
    SecondFragment secondFragment = new SecondFragment();
    
    getFragmentManager()
        .beginTransaction()
        .replace(R.id.fragment_container, secondFragment)
        .addToBackStack("second frag")
        .commit();
  1. Here is how back press can be handled, below code should be present in the parent Activity.
     public void onBackPressed() {
        if(getFragmentManager().getBackStackEntryCount() <= 1) {
           super.onBackPressed();
        } else {
           getFragmentManager().popBackStack();
        }
     }
user1506104
  • 6,554
  • 4
  • 71
  • 89
Sunita
  • 1,219
  • 12
  • 16
5

Did you check your XML and see if the main layout is Frame Layout? If not then, use the Frame Layout instead. This will resolve overlapping issue. That's the only way to fix. I tried the "accepted" answer while searching for a solution for this problem and it didn't work.

David Dimalanta
  • 548
  • 6
  • 19
  • 1
    it works for me, thanks. New fragment was ConstraintLayout by default on create. I have to change it to FrameLayout, then they are no longer overlapping. – andre_northwind Apr 21 '20 at 12:11
4

Another problem can be related to using android.R.id.content as a container. I've just created FrameLayout and use id from there.

irudyak
  • 2,271
  • 25
  • 20
2
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();}
Mohit Taparia
  • 49
  • 1
  • 13
0

when you have a overlap fragment, maybe your background of your fragment is transparent, you need put a android:background="@color/white"' inside your fragment propeties

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

and white you need put inside of the colors.xml #FFFFFF in the rest folder.

0

I have sometimes the same problem, but my problem is not related to different fragment managers (getSupportFragmentManager(), getFragmentManager()). I think there is still another problem. In my case, when I open the navigation drawer, I always delete old fragments on every menu option, for example:

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

It's not possible to get into a sub menu without the navigation drawer, so the fragments are basically always removed. In some cases, after I remove and add a fragment again inside an Activity it suddenly overlaps with another (previous) fragment?! But why does the fragment manager suddenly finds previous fragments? That can either mean that the fragment manager is buggy and it does not remove old fragments, or that something other is broken.
My thought is, that it's somehow the fault of Android Studio or any other adb development tool which is used by it. Why I think that is, because Android Studio sometimes seem to loose the instance of the running app. Probably this problem is somehow related to the same issue: Android Studio not deploying changes to app. I didn't figure out yet when this happens. What I know is that it can't be a programming issue, because it's not reproducible after I relaunched the app by Android Studio. I guess there are somehow any background processes hanging which causes multiple instances of Activities, Fragments, fragment managers and so on. Furthermore it's not just this bug. I saw a lot of strange behaviours in past which are similar to this one. (For example the behaviours suddenly disappeared when the app was not started by IDE).

Community
  • 1
  • 1
Bevor
  • 8,396
  • 15
  • 77
  • 141
0

It all has to do with the engineering behind the replace and the addToBackStack methods.

The replace method will actually do two things. Hide the existing fragment (let's say A) and add a new one (let's say B) in the container.

Adding that transaction to the back stack will do the opposite. Remove B and add A.

So, the solution to your problem is
1. use addToBackStack method.
2. make sure that the reverse replacement of fragments is the correct order

The second suggestion is really important, because it is pretty often that at some point the current fragment is not removed and another one is added, which causes the two fragments showing at the same time.

ichalos
  • 497
  • 5
  • 9
0

Making the background color white solved it for me too. I think this is a bug or and implementation issue in the Android fragmentment manager. I was implementing my replace and popBackStack() correctly.

daniekpo
  • 157
  • 3
  • 9
0

When I had a problem like this it appeared that I was adding one fragment with childFragmentManager and another with parent's fragmentManager, so check that you use same type of fragment manager.

Olga Sokol
  • 11
  • 1
  • 3
0

I don't think implementing a white background is a safe solution although it may be convenient. Basically the problem occurs because fragment manager is confused about which fragment to pop.

backstack looks like this and thinks your on frag 4 1->2, 2->3, 3->4 but your actually on frag 6 for some reason so popbackstack goes

remove(4) add(3) <- now you have 3(new) and 6(left behind) blended together

To better control my navigation I keep track of my current/previous fragments and replace them like this. This allows my app to control fragment navigation.

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

Secondly, I believe the fragmentmanager.replace() method is a better alternative. Not sure if that is available to OP at the time.

Third, to handle the androids native back press you need to be able to scroll back indefinitely. Many people recommend not adding the first fragment to back stack by not using this line.

fragmentTransaction.addToBackStack(null);

However if that's the case you must check if its the first time the app has loaded. If its not and you exclude this line then your app will have these issues whenever you navigate through this fragment. I prefer to leave it in place and do the following instead.

Not sure if this is considered a good solution but it works very well.

1- get backstack count 2- remove all existing frags 3- keep track of you fragment objects 4- if its the last frag in the stack the user wishes to exit and since we added the main activity to the back stack we need to double pop

@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();
        }
cagney
  • 492
  • 3
  • 11
0

I found simple and clean solution. For me problem was in execution fragment transaction in every call of onCreate() of my Activity. Now I perform transaction only if savedInstanceState == null

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        if (savedInstanceState == null) {
        // replace fragment 
        }
    }
Ivan Syabro
  • 136
  • 1
  • 6
0

Instead of using fragment as the container for the fragments, use FragmentContainerView. That solved the issue for me

Crucialjun
  • 193
  • 1
  • 8