首页 文章

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

提问于
浏览
45

我正在开发一个使用导航抽屉图案的应用程序(使用DrawerLayout) .

每次单击抽屉的项目,都会替换主容器中的片段 .

但是,我不确定何时是进行片段交易的合适时机?抽屉开始关闭时?或者关闭后?

在谷歌的documentaion example中,您可以看到他们在项目点击后立即进行交易,然后关闭抽屉 .
结果,抽屉看起来很迟钝而且不平滑,看起来非常糟糕(它也发生在我的应用中) .

GmailGoogle Drive应用程序中,另一方面,看起来他们在抽屉关闭后正在进行交易(我是对吗?) .
结果,抽屉没有延迟且非常平滑,但至少需要大约1秒钟(抽屉关闭所需的时间)才能看到下一个片段 .

在立即进行片段交易时,似乎抽屉没有办法顺畅 .

你觉得怎么样?

提前致谢!

7 回答

  • 25

    是的,不能同意,执行一个片段(带有视图)事务导致布局传递,导致动画视图上的janky动画,引用 DrawerLayout docs

    DrawerLayout.DrawerListener可用于监视抽屉视图的状态和动作 . 避免在动画期间执行昂贵的操作,例如布局,因为它可能导致口吃;尝试在STATE_IDLE状态期间执行昂贵的操作 .

    因此,请在抽屉关闭或有人修补支持库以某种方式修复:)之后执行您的片段事务

  • 23

    另一种解决方案是在关闭抽屉后创建 Handler 并发布延迟 Runnable ,如下所示:https://stackoverflow.com/a/18483633/769501 . 这种方法的好处是,如果您等待 DrawerListener#onDrawerClosed() ,您的碎片将比它们更快地被替换,但当然任意延迟并不能100%保证抽屉动画将及时完成 .

    也就是说,我使用了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);
        }
    }
    
  • 5

    这就是我为实现类似于Gmail应用程序的流畅交易动画所做的工作:

    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

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

    希望对你有所帮助! :-)

  • 15

    我知道这个问题已经过时了,但我遇到了同样的问题并且认为我会发布我的解决方案,因为我认为这是一个比添加硬编码延迟时间更好的实现 . 我所做的是在执行任务之前使用 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
    }
    

    然后在 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);
        }
    }
    
  • 1

    只需在处理程序中编写代码并将200 ms延迟 .

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

    而不是延迟您的商品点击,这可能会让您的应用感到缓慢 . 我只是推迟关闭mDrawerLayout . 我也不会使用 DrawerLayout.OnDrawerListener onClose(...) 因为那些回调调用太慢了 .

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

    如果您希望它平滑且没有任何延迟,请将抽屉保持打开状态,然后在返回时将其关闭(在onRestart()方法中) .

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

    副作用是返回时的(快速)动画,但这可能是可以接受的 .

相关问题