DrawerLayout's item click - When is the right time to replace fragment?
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:
DrawerLayout.DrawerListener can be used to monitor the state and motion of drawer views. Avoid performing expensive operations such as layout during animation as it can cause stuttering; try to perform expensive operations during the STATE_IDLE state.
So please perform your fragment transactions after the drawer is closed or somebody patches the support library to somehow fix that :)
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. 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.
That said, I use a 200ms delay and it works wonderfully.
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); }}
This is what I do to achieve an smooth transaction animation similar to Gmail app:
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();...@Overridepublic 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! :-)