I am at trying to to get my navigation drawer to run smoothly as there is a stutter/delay in transition when opening and closing the drawer. I would like this to run perfectly. Any help?
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final MediaPlayer mp = MediaPlayer.create(this, R.raw.firsteps);
mp.start();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setItemIconTintList(null);
navigationView.setNavigationItemSelectedListener(this);
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().replace(R.id.content_frame, new MainFragment()).commit();
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
startActivity(new Intent(getApplicationContext(),Testing.class));
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
//final MediaPlayer mp = MediaPlayer.create(this, R.raw.xlophone);
FragmentManager fm = getSupportFragmentManager();
int id = item.getItemId();
if (id == R.id.car_stories) {
fm.beginTransaction().replace(R.id.content_frame,new ChildrensList()).commit();
//mp.start();
} else if (id == R.id.car_places) {
fm.beginTransaction().replace(R.id.content_frame,new ImportFragment()).commit();
//mp.start();
} else if (id == R.id.nav_slideshow) {
} else if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
Documentation: Click
Try this:
//Use Handler().postDelayed
@Override
public boolean onNavigationItemSelected(MenuItem item) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
switch (item.getItemId()) {
case: R.id.example1:
// do something
break;
case: R.id.example2:
// do something
break;
default: // do something
}
}, 200);
drawer.closeDrawer(GravityCompat.START);
return true;
}
In my humble opinion you need to avoid calling 'new' every click.
To fix this you can use constant values to navigation drawer's android:layout_width
and android:layout_height
attributes ie.
android:layout_width="@dimen/navigation_drawer_width"
android:layout_height="match_parent"
You may also want to enable hardware acceleration on activity in AndroidManifest.xml
<activity
android:name=".ui.SomeActivity"
android:hardwareAccelerated="true" />
The lag is caused by two heavy operations (fragment replacement and drawer animation) happening in the same thread (main thread aka UI thread).
One way to address this problem is to call the replacement of fragments after the drawer completely closes. In this way the two operations will not happen simultaneously.
In addition, it's a nice design implementation to cross fade a progress bar with the fragment container.
Inside your Activity
you should have something like this:
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// Show progress bar and hide content container
crossfade(progressBar, container, false)
drawerLayout?.addDrawerListener(object : DrawerLayout.DrawerListener {
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}
override fun onDrawerOpened(drawerView: View) {}
override fun onDrawerStateChanged(newState: Int) {}
override fun onDrawerClosed(drawerView: View) {
// This method will be called after drawer animation finishes
// Perform the fragment replacement
when (item.itemId) {
R.id.drawer_item_1 -> {
supportFragmentManager.beginTransaction()
.replace(R.id.container, MyFragmentOne.newInstance())
.addToBackStack(null)
.commit()
}
R.id.drawer_item_2 -> {
supportFragmentManager.beginTransaction()
.replace(R.id.container, MyFragmentTwo.newInstance())
.addToBackStack(null)
.commit()
}
}
// Cross fade back the content container and hide progress bar
crossfade(container, progressBar, false)
// Remove this listener so close by, for example, swiping do not call it again
drawerLayout.removeDrawerListener(this)
}
})
// Closes the drawer, triggering the listener above
drawerLayout.closeDrawer(GravityCompat.START)
return true
}
private fun crossfade(viewIn: View, viewOut: View, animateViewOut: Boolean = true) {
val crossfadeDuration = 200L
// Set the content view to 0% opacity but visible, so that it is visible
// (but fully transparent) during the animation.
viewIn.alpha = 0f
viewIn.visibility = View.VISIBLE
viewIn.bringToFront()
// Animate the in view to 100% opacity, and clear any animation
// listener set on the view.
viewIn.animate()
.alpha(1f)
.setDuration(crossfadeDuration)
.setListener(null)
// Animate the out view to 0% opacity. After the animation ends,
// set its visibility to GONE as an optimization step (it won't
// participate in layout passes, etc.)
viewOut.animate()
.alpha(0f)
.setDuration(if (animateViewOut) crossfadeDuration else 0)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
viewOut.visibility = GONE
}
})
}
Inside your xml, you should have something like this:
...
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:openDrawer="start">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigationView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/drawer" />
</android.support.v4.widget.DrawerLayout>
....
Just close the Drawer in some delay, it makes close animation smooth
navigation.setNavigationItemSelectedListener { menuItem ->
// make closing side-menu smooth
Completable.timer(100, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.subscribe {
drawer.closeDrawer(GravityCompat.START)
}.addTo(disposable)
when(menuItem.itemId){
R.id.sideMenuDashboard ->
navController.navigate(R.id.fragment1)
R.id.sideMenuProfile ->
navController.navigate(R.id.fragment2)
}
true
}
After call drawerLayout.closeDrawers() create a new Thread
new Thread(new Runnable() {
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(300);
//Here call you fragmentManager
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
of course you can vary MILISECONDS as you want. Sorry my english
The lag is caused by two heavy operations (fragment replacement and drawer animation) happening in the same thread (main thread aka UI thread).
In my case navigation header background image size is large, so its works on high performance devices but lack on low performance devices.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.