简体   繁体   English

DrawerLayout的项目点击 - 何时是替换片段的正确时间?

[英]DrawerLayout's item click - When is the right time to replace fragment?

I'm developing an application which uses the navigation drawer pattern (With DrawerLayout). 我正在开发一个使用导航抽屉图案的应用程序(使用DrawerLayout)。

Each click on a drawer's item, replaces the fragment in the main container. 每次单击抽屉的项目,都会替换主容器中的片段。

However, I'm not sure when is the right time to do the fragment transaction? 但是,我不确定何时是进行片段交易的合适时机? When the drawer starts closing? 抽屉开始关闭时? Or after it is closed? 或者关闭后?

In google's documentaion example , you can see that they are doing the transaction right after the item click, and then close the drawer. 在google的documentaion示例中 ,您可以看到他们在项目单击后立即执行事务,然后关闭抽屉。
As a result, the drawer seems laggy and not smooth, and it looks very bad (It happens in my application too). 结果,抽屉看起来很迟钝而且不平滑,看起来非常糟糕(它也发生在我的应用中)。

In Gmail and Google Drive applications, on the other way, It seems like they are doing the transaction after the drawer closed (Am I Right?). GmailGoogle云端硬盘应用程序中,另一方面,它似乎是在抽屉关闭后进行交易(我是对吗?)。
As a result, the drawer is not laggy and very smooth, BUT it takes about 1 second (the time it takes to the drawer get closed) at least, to see the next fragment. 结果,抽屉没有延迟且非常平滑,但至少需要大约1秒钟(抽屉关闭所需的时间)才能看到下一个片段。

It seems like there is no way the drawer will be smooth when immediately doing fragment transaction. 在立即进行片段交易时,似乎抽屉没有办法顺畅。

What do you think about that? 你觉得怎么样?

Thanks in advance! 提前致谢!

Another solution is to create a Handler and post a delayed Runnable after you close the drawer, as shown here: https://stackoverflow.com/a/18483633/769501 . 另一种解决方案是在关闭抽屉后创建一个Handler并发布延迟的Runnable ,如下所示: https//stackoverflow.com/a/18483633/769501 The benefit with this approach is that your fragments will be replaced much sooner than they would be if you waited for DrawerListener#onDrawerClosed() , but of course the arbitrary delay doesn't 100% guarantee the drawer animation will be finished in time. 这种方法的好处是,如果您等待DrawerListener#onDrawerClosed() ,您的片段将被更快地替换,但当然任意延迟不能100%保证抽屉动画将及时完成。

That said, I use a 200ms delay and it works wonderfully. 也就是说,我使用了200ms的延迟,它运行得非常好。

private class DrawerItemClickListener implements OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
        drawerLayout.closeDrawer(drawerList);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                switchFragments(position); // your fragment transactions go here
            }
        }, 200);
    }
}

Yup, couldn't agree more, performing a fragment (with view) transaction results in a layout pass which causes janky animations on views being animated, citing DrawerLayout docs : Yup,不能同意,在一个布局传递中执行一个片段(带有视图)事务结果会导致动画视图上的DrawerLayout动画,引用DrawerLayout 文档

DrawerLayout.DrawerListener can be used to monitor the state and motion of drawer views. DrawerLayout.DrawerListener可用于监视抽屉视图的状态和动作。 Avoid performing expensive operations such as layout during animation as it can cause stuttering; 避免在动画期间执行昂贵的操作,例如布局,因为它可能导致口吃; try to perform expensive operations during the STATE_IDLE state. 尝试在STATE_IDLE状态期间执行昂贵的操作。

So please perform your fragment transactions after the drawer is closed or somebody patches the support library to somehow fix that :) 因此,请在抽屉关闭或有人修补支持库以某种方式修复:)之后执行您的片段事务

This is what I do to achieve an smooth transaction animation similar to Gmail app: 这就是我为实现类似于Gmail应用程序的流畅交易动画所做的工作:

activity_drawer.xml activity_drawer.xml

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!-- The main content view -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- The navigation drawer -->
    <ListView 
    android:id="@+id/left_drawer"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="left"
        android:choiceMode="singleChoice" />

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

DrawerActivity.java DrawerActivity.java

private Fragment mContentFragment;
private Fragment mNextContentFragment;
private boolean mChangeContentFragment = false;

private Handler mHandler = new Handler();

...

@Override
public void onCreate(Bundle savedInstanceState) {
    ...

    mDrawerLayout.setDrawerListener(new DrawerListener());

    mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

    ...
}

....

private class DrawerItemClickListener implements ListView.OnItemClickListener {

    @Override
    public void onItemClick(AdapterView parent, View view, int position, long id) {
        getSupportFragmentManager().beginTransaction().remove(mContentFragment).commit();

        switch (position) {
            case 0:
                mNextContentFragment = new Fragment1();
                break;

            case 1:
                mNextContentFragment = new Fragment2();
                break;

            case 2:
                mNextContentFragment = new Fragment3();
                break;
        }

        mChangeContentFragment = true;

        mDrawerList.setItemChecked(position, true);

        mHandler.postDelayed(new Runnable() {

            @Override
            public void run() {
                mDrawerLayout.closeDrawer(mDrawerList);
            }           
        }, 150);
    }
}

private class DrawerListener implements android.support.v4.widget.DrawerLayout.DrawerListener {

    @Override
    public void onDrawerClosed(View view) {
        if (mChangeContentFragment) {
             getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).replace(R.id.content_frame, mNextContentFragment).commit();

             mContentFragment = mNextContentFragment;           
             mNextContentFragment = null;

             mChangeContentFragment = false;
         }
     }
 }

Hope that helps you! 希望对你有所帮助! :-) :-)

I know this question is old but I ran into the same problem and figured I would post my solution as I think it is a better implementation than adding a hardcoded delay time. 我知道这个问题已经过时了,但我遇到了同样的问题并且认为我会发布我的解决方案,因为我认为这是一个比添加硬编码延迟时间更好的实现。 What I did was use the onDrawerClosed function to verify that the drawer IS closed before doing my task. 我所做的是在执行任务之前使用onDrawerClosed函数来验证抽屉是否已关闭。

//on button click...
private void displayView(int position) {
    switch (position) {
    //if item 1 is selected, update a global variable `"int itemPosition"` to be 1
    case 1:
        itemPosition = 1;
        //();
        break;
    default:
        break;
    }

    // update selected item and title, then close the drawer
    mDrawerList.setItemChecked(position, true);
    mDrawerList.setSelection(position);
    mDrawerLayout.closeDrawer(mDrawerList); //close drawer
}

and then in onDrawerClosed , open the corresponding activity. 然后在onDrawerClosed ,打开相应的活动。

public void onDrawerClosed(View view) {
    getSupportActionBar().setTitle(mTitle);
    // calling onPrepareOptionsMenu() to show action bar icons
    supportInvalidateOptionsMenu();
    if (itemPosition == 1) {
        Intent intent = new Intent(BaseActivity.this, SecondActivity.class);
        startActivity(intent);
    }
}

Just write your code in a handler and put 200 ms delay. 只需在处理程序中编写代码并放置200毫秒的延迟。

 new Handler().postDelayed(new Runnable() {
  @Override
   public void run() {
       openSelectionDrawerItem(position);          
   }
 }, 200);

Instead of delaying your item clicks which may make your app feel slow. 而不是延迟您的商品点击,这可能会让您的应用感到缓慢。 I would just delay the closing of the mDrawerLayout. 我只是推迟关闭mDrawerLayout。 I would not use the DrawerLayout.OnDrawerListener onClose(...) either because those callbacks are so slow to be called. 我不会使用DrawerLayout.OnDrawerListener onClose(...) ,因为这些回调调用的速度很慢。

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        mDrawerLayout.closeDrawer(GravityCompat.START);
    }
}, 200);

If you want it smooth and without any delay, leave the drawer open and close it afterwards when returning (in the onRestart() method). 如果您希望它平滑且没有任何延迟,请将抽屉保持打开状态,然后在返回时将其关闭(在onRestart()方法中)。

@Override
protected void onRestart() {
    // TODO Auto-generated method stub
    super.onRestart();
    mDrawerLayout.closeDrawer(mDrawerList);     
}

The side effect is an (speedy) animation when returning, but this might be acceptable. 副作用是返回时的(快速)动画,但这可能是可以接受的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM