Fragments overlapping with DrawerLayout/NavigationView

1.6k Views Asked by At

Using a DrawerLayout with a NavigationView and a FrameLayout I want to switch Fragments. That works great. However, if I switch too quickly, then the Fragments overlaps...

It is like executePendingTransactions() does not work.

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <include layout="@layout/toolbar" />

        <FrameLayout
            android:id="@+id/frameLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </LinearLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/navigationView"
        android:layout_width="@240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@color/transparent"
        android:dividerHeight="0dp"
        app:menu="@menu/navigationdrawer" />

</android.support.v4.widget.DrawerLayout>

If I switch Fragments (too) rapidly (manually or by code with a 750ms delay on my Nexus 5), I get both Fragments to overlap, with the second Fragment having the touch enabled BUT the first Fragment being on top...

The first Fragment contains an ImageView and TextViews. The second Fragment contains a TabLayout and a ViewPager (if that could have anything to day with my issue). Yes I'm using AppCompat 22.2.0 and Design 22.2.0 libraries.

If I set a background color to both, then I can only see the first Fragment, and it never changes.

I tried popBackStackImmediate(), executePendingTransactions(), remove(fragment), android:fitsSystemWindows="true", Android: fragments overlapping issue, delaying, and other things, without success.

@Override
protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // ...

    mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(final MenuItem menuItem) {
            navigationDrawer(menuItem.getItemId());
            return true;
        }
    });

    if (savedInstanceState == null) {
        final MenuItem menuItem = mNavigationView.getMenu().getItem(0);
        if (menuItem != null) {
            navigationDrawer(menuItem.getItemId());
        }
    }
}

private void navigationDrawer(final int itemId) {
    final Fragment fragment = getFragment(itemId);
    getSupportFragmentManager().beginTrasaction()
        .replace(R.id.frameLayout, fragment)
        .addToBackStack(null)
        .commit();
    mNavigationView.getMenu().findItem(itemId).setChecked(true);
    mDrawerLayout.closeDrawer(mNavigationView);
    supportInvalidateOptionsMenu();
}

@Override
public boolean onOptionsItemSelected(final MenuItem item) {
    switch (item.getItemId()) {
        case R.id.menu_first:
        case R.id.menu_second:
        case R.id.menu_third:
            navigationDrawer(item.getItemId());
            return true;
    }
    return super.onOptionsItemSelected(item);
}

EDIT

In my onCreate() I was doing this:

if (savedInstanceState == null) {
    final MenuItem menuItem = mNavigationView.getMenu().getItem(0);
    if (menuItem != null) {
        navigationDrawer(menuItem.getItemId());
    }
}

Which turns out to make a call too rapidly. Removing this code solved my issue (temporally, see below).

I still don't know why executePendingTransactions() did not prevent such weird issue...

EDIT 2

I thought about keeping a boolean (init to false) to keep track of when a Fragment transaction takes place. I set it to true in my navigationDrawer() and to false in Fragment.onResume(). Still no go...

So: still having problem on my MainFragment that loads an image using Picasso and switching too rapidly (800ms) to another Fragment: they still overlap...

2

There are 2 best solutions below

2
On BEST ANSWER

In my onCreate() I was doing this:

    if (savedInstanceState == null) {
        final MenuItem menuItem = mNavigationView.getMenu().getItem(0);
        if (menuItem != null) {
            navigationDrawer(menuItem.getItemId());
        }
    }

Which turns out to make a call too rapidly. Removing this code solved my issue.

I still don't know:

why executePendingTransactions() did not prevent such weird issue...

EDIT

Still having problem on my MainFragment that loads an image using Picasso and switching too rapidly (800ms) to another one: they still overlap...

EDIT 2

So I now use a boolean to mark if my Activity is transitioning a Fragment or not, with a minimal timer of 1s second between switches.

In my Fragments onViewCreated():

if (view != null) {
    view.post(new Runnable() {
        @Override
        public void run() {
            // Activity might be null
            getActivity().setTransitioning(false);
        }
    });
}

And in my navigationDrawer():

if (isTransitioning()) {
    // Switching Fragments too fast
    return false;
}
1
On

You may try this ... It will delay your frequent click ...

private final Handler mDrawerActionHandler = new Handler();
private static final long DRAWER_CLOSE_DELAY_MS = 250;

mDrawerActionHandler.postDelayed(new Runnable() {
      @Override
      public void run() {
        // your navigation code goes here
      }
}, DRAWER_CLOSE_DELAY_MS);