与DrawerLayout/NavigationView重叠的碎片

7
使用带有NavigationView和FrameLayout的DrawerLayout来切换Fragment,效果非常好。但是,如果我切换得太快,那么Fragment将会重叠... 这就像executePendingTransactions()不起作用一样。
<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>

如果我(手动或通过代码在我的Nexus 5上延迟750毫秒)快速切换片段,我会使两个片段重叠,第二个片段具有触摸功能,但第一个片段位于顶部... 第一个片段包含ImageView和TextView。第二个片段包含TabLayout和ViewPager(如果这可能与我的问题有关)。是的,我正在使用AppCompat 22.2.0和Design 22.2.0库。如果我为两者设置背景颜色,那么我只能看到第一个片段,并且它永远不会更改。我尝试了popBackStackImmediate(),executePendingTransactions(),remove(fragment),android:fitsSystemWindows =“true”,{{link1:Android:fragments overlapping issue}},延迟以及其他一些事情,但没有成功。
@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);
}

编辑

在我的onCreate()中,我正在执行以下操作:

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

这导致调用过快。删除此代码解决了我的问题(暂时性解决,见下文)。

我仍然不知道为什么executePendingTransactions()没有防止这种奇怪的问题...

编辑2

我考虑保留一个布尔值(初始化为false)来跟踪Fragment事务发生的时间。我在navigationDrawer()中将其设置为true,在Fragment.onResume()中将其设置为false。还是不行...

所以:仍然存在问题,即我的MainFragment使用Picasso加载图像,并在800ms内太快地切换到另一个Fragment:它们仍然重叠...


@Moinkhan 哪一部分?我相信我已经发布了相关部分。这是一个基本的DrawerLayout/NavigationView实现。 - shkschneider
您提供的代码完美无缺。因此,我认为问题可能出在这里未提供的代码上... - Moinkhan
似乎点击事件在onCreate之前就已经运行了,你调试过了吗? - Sulfkain
怎么可能?我竟然能够用自己的手指引发这个错误。所以用户界面已经构建完成并且已经执行了onCreate()函数。 - shkschneider
我认为你的问题是由于navigationDrawer()方法从onCreate()方法中被调用(当savedInstance为空时),以及NavigationView的监听器。在某些情况下,您可能会添加比您想要的更多的片段(这就是为什么从onCreate中删除代码似乎起作用的原因)。此外,navigationDrawer()方法应该进行一些检查,而不是盲目地添加片段,例如检查已经存在的片段容器(对于初始的onCreate调用),当用户选择相同的菜单选项时不添加片段... - user
显示剩余3条评论
2个回答

1

您可以尝试这个方法...

它将延迟您频繁的点击操作...

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

我已经想到并尝试了这种方法,但不起作用(而且这也无法解释我的问题)。无论如何,感谢您的建议。 - shkschneider

0
在我的onCreate()中,我正在做这个:
    if (savedInstanceState == null) {
        final MenuItem menuItem = mNavigationView.getMenu().getItem(0);
        if (menuItem != null) {
            navigationDrawer(menuItem.getItemId());
        }
    }

结果证明调用太快了。删除这段代码解决了我的问题。

我仍然不知道:

为什么executePendingTransactions()没有防止这种奇怪的问题...

编辑

我的MainFragment仍然存在问题,它使用Picasso加载图像,并在800毫秒内快速切换到另一个图像:它们仍然重叠...

编辑2

因此,我现在使用布尔值来标记我的Activity是否正在转换Fragment,并在切换之间设置最小计时器为1秒。

在我的FragmentonViewCreated()中:

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

在我的navigationDrawer()中:
if (isTransitioning()) {
    // Switching Fragments too fast
    return false;
}

另一种方法是在我的“navigationDrawer()”方法顶部检查传递的“Activity”是否已通过“onResume()” 。现在即使出现错误代码也可以工作。 - shkschneider
然而那并没有起作用:我设置了一个布尔值来表示是否有交易正在进行,并让我的片段在onResume()中将其设置为false。但仍然不起作用... - shkschneider

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接