Navigation drawer doesn't close - android

The navigation drawer in my app is not closing. I am using activities instead of fragments. When i click on any item in the listview, it opens other activities as it should but when i go back, the drawer is still open. I have tried using DrawerLayout.closeDrawers(); but it did not work. How do I close the navigation drawer?
Here is my code:
Java
public class MainActivity extends FragmentActivity {
final String[] data ={"Aluminium","Gold","Zinc"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data);
final DrawerLayout drawer = (DrawerLayout)findViewById(R.id.drawer_layout);
final ListView navList = (ListView) findViewById(R.id.left_drawer);
navList.setAdapter(adapter);
navList.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, final int pos,long id){
switch (pos){
case 0:
Intent i = new Intent(MainActivity.this,Aluminium.class);
startActivity(i);
break;
case 1:
Intent i2 = new Intent(MainActivity.this,Gold.class);
startActivity(i2);
break;
case 2:
Intent i3 = new Intent(MainActivity.this,Zinc.class);
startActivity(i3);
break;
}
}
});
}
}
XML
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:orientation="horizontal"
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:background="#000000"
android:layout_height="match_parent" >
</FrameLayout>
<ListView android:id="#+id/left_drawer"
android:layout_width="220dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="1dp"
android:background="#000000"/>
</android.support.v4.widget.DrawerLayout>

have you tried :
mDrawerLayout.closeDrawer(drawerListView);
You can add this before calling startActivity()

In continuation to others answers and # Chinmay Dabke question of 'but the drawer closes half then pauses and then closes fully' in one of the comments, here is what you could do:
first as others suggested,
this line is missing. drawer.closeDrawer(navList);
And as far as the pausing of drawer is concerned while closing, you could do something like this.
use a Runnable and a Handler like this:
mRunnable = = new Runnable() {
#Override
public void run() {
//say
selectItem(pos); //Implement your switch case logic in this func
}
}
and then in the onDrawerClosed overrided method
#Override
public void onDrawerClosed(View view) {
if (mRunnable != null) {
mHandler.post(mRunnable);
mRunnable = null;
}
}
Hope this helps!
I would suggest you to use fragments for navigation drawer and to solve this issue of drawer not closing properly, I found this article very useful (using fragments). http://www.michenux.net/android-asynctask-in-fragment-best-pratices-725.html

Call
drawer.closeDrawer(navList);
in onItemClick() method

Try
drawer.closeDrawer(Gravity.START);
Your drawer gravity is start so Use that to close the corresponding drawer

I didn't see any code where you are closing the ListView from drawer... close the ListView Drawer on ListItem click...
navList.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, final int pos,long id){
drawer.closeDrawer(navList);
switch (pos){
case 0:
Intent i = new Intent(MainActivity.this,Aluminium.class);
startActivity(i);
break;
case 1:
Intent i2 = new Intent(MainActivity.this,Gold.class);
startActivity(i2);
break;
case 2:
Intent i3 = new Intent(MainActivity.this,Zinc.class);
startActivity(i3);
break;
}
}
});

You need to close the drawer on list item click
drawer.closeDrawer(navList);
Also what is the use of FrameLayout in your xml. It is not used as a container to add or replace fragments

call the drawer.closeDrawer(navList); function before switch case

use
if(drawer.isDrawerOpen(navList))
{
drawer.closeDrawer(navList);
}
In onResume() and start of onItemClick() method.
or you can try another approach..run a Ui thread when you are selecting drawer item
private void selectDrawerItemItem(final int position){
//Toast.makeText(getApplicationContext(), "ItemClicked", Toast.LENGTH_SHORT).show();
darwer.closeDrawer(navList);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Fragment fragment = new Fragment(Activity.this);
Bundle args = new Bundle();
args.putInt(Fragment.ARG_PLANET_NUMBER, position);
fragment.setArguments(args);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).commit();
// update selected item and title, then close the drawer
navList.setItemChecked(position, true);
setTitle(" " + navListTitles[position]);
}
}, 200);
// update the main content by replacing fragments
}

I was having the same problem.
I used
mDrawerLayout.closeDrawer(drawerListView);
before starting my new activity. It beautifully slides the drawer back in.

private DrawerLayout mDrawerLayout;
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerLayout.closeDrawers();
it works

Here is the code:
Lets say you have the drawer class
in your activity call the class as and make a vaiable and assign it(put the drawer layout within a fragment for smoother user experience)
Drawer drawer;
drawer = (Drawer)getActivity().getSupportFragmentManager().findFragmentById(R.id.theid);
drawer.mDrawerLayout.closeDrawer(Gravity.END);
//End for right and Start for left
Hope it helps

Related

Navigation Drawer Android Example: How to load a specific Fragment thats not the Fragment Frame Container upon Loading

I've implemented a multi view application with the Nav Drawer example on android developers, everything works fine and is implemented correctly. I'm using the dynamic way of loading fragments. I have one main activity that loads a fragment frame container. When i select options in the nav drawer My onclick listener allows me to change fragments with no problems and loads them into the frame container. This frame container is contained in my main activity xml file. The relevant id is linked in the oncreate method exactly like it should and thats fine. The problem I have is that this activity is obviously blank when loaded and i want it to populate the first item from my string array without having to touch the nav menu. I'm sure the solution is simple but its still evading me!
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
\\ this loads my content frame to display a fragment when i select a nav bar option
setContentView(R.layout.activity_my);
activity_my.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:entries="#array/futurists"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
/* The click listener for ListView in the navigation drawer */
private class DrawerItemClickListener implements ListView.OnItemClickListener
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
displayView(position);
}
}
// Method that updates content frame with different fragments
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new Title();
break;
case 1:
fragment = new Activity1();
break;
case 2:
fragment = new Activity2();
break;
case 3:
fragment = new Activity3();
break;
case 4:
fragment = new Activity4();
break;
case 5:
fragment = new Activity5();
break;
case 6:
fragment = new Activity6();
break;
case 7:
fragment = new Activity7();
break;
case 8:
fragment = new Activity8();
break;
case 9:
fragment = new Activity9();
break;
case 10:
fragment = new Activity10();
default:
break;
}
if (fragment != null)
{
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment).addToBackStack(null).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(mNames[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
Above is my onclick listener which selects the various fragments for population in the content frame.
My question is how do i load the fragment Title without having to touch the an option in the navigation drawer when the activity loads. I was having a look at the application lifecycle and i tried various experiments with onCreateView after the oncreate method but that doesn't work either. Any help would be greatly appreciated. Thanks

Running ActionBarActivity instead of Fragment on DrawerLayout

I want to making DrawerLayout for my new android app. But I need to use activity on same activity.
How can I handle it, I have code looks like this :
my_activity.java; (has a lot of code for list of menu, swipe vs, But I just add lines of my problems)
switch (position) {
case 0:
fragment = new HomeFragment();
break;
Here is my problem. I want to run activity file at this step but I cant. I wanna show some activity file case : 0, I tried everything I know But I cant do it.
ACTUALLY I m a bit of confused for this fragment & activity problems.
Thank you for helps.
First of all, your activity xml (the one you wanna use with the Navigation Drawer) must contain a <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android">
as its root element and a listview (last on the xml hierarchy)
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#android:color/background_light"
android:choiceMode="singleChoice" />
In your activity you should have:
DrawerLayout drawerLayout;
ListView drawerList;
ActionBarDrawerToggle drawerToggle;
...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout,
R.drawable.ic_drawer, R.string.Open, R.string.Close);
drawerLayout.setDrawerListener(drawerToggle);
drawerList.setAdapter(new youradaptertype());
drawerList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
switch (arg2) {
case 0:
Intent l = new Intent(MainActivity.this,
FriendActivity.class);
startActivity(l);
break;
case 1:
Intent j = new Intent(MainActivity.this, RequestActivity.class);
startActivity(j);
break;
case 2:
Intent i = new Intent(MainActivity.this,
SettingsActivity.class);
startActivity(i);
break;
...
}
drawerLayout.closeDrawer(drawerList);
}
});
Inside each "case" statement, to start an activity you should use the Intent and start a new activity. If you simply wanna change fragments (instead of starting new activities) inside the "case" you should to something like this:
getSupportFragmentManager().beginTransaction()
.replace(YOUR_ROOT_VIEW_ID, new fragmenttobeinstantiated())
//optinal
.addToBackStack(null).commit();
See if it helps !

get selected item - ListView Android

I know this has been asked here but the answers were quite confusing. I have 3 items in my ListView. They are "Aluminium", "Gold" and "Zinc". Through each one of them, I want to start different activities and for that I have created the 3 activities which i named "Aluminium.java","Gold.java" and "Zinc.java"
I have used this ListView in a drawer layout for the navigation drawer. I implemented navigation drawers through the code given below which i got from a site.This code changes fragments and its not working properly. Instead of fragments, I want to switch activities.
I want to achieve 3 things:
Switch between activities through the listview in the navigation drawer.
To achieve point 1, I want to get the clicked list item and then use intents.
I want all the 3 activities to have this navigation drawer.
Sorry if its too dumb but I am a beginner. Please help me out with the code.
Java code
public class MainActivity extends FragmentActivity {
final String[] data ={"Aluminium","Gold","Zinc"};
final String[] fragments ={
"com.Chinmay.navigationdrawer.Gold",
"com.Chinmay.navigationdrawer.Aluminium",
"com.Chinmay.navigationdrawer.Zinc"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data);
final DrawerLayout drawer = (DrawerLayout)findViewById(R.id.drawer_layout);
final ListView navList = (ListView) findViewById(R.id.left_drawer);
navList.setAdapter(adapter);
navList.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, final int pos,long id){
drawer.setDrawerListener( new DrawerLayout.SimpleDrawerListener(){
#Override
public void onDrawerClosed(View drawerView){
super.onDrawerClosed(drawerView);
android.support.v4.app.FragmentTransaction tx = getSupportFragmentManager().beginTransaction();
tx.replace(R.id.content_frame, Fragment.instantiate(MainActivity.this, fragments[pos]));
tx.commit();
}
});
drawer.closeDrawer(navList);
android.support.v4.app.FragmentTransaction tx = getSupportFragmentManager().beginTransaction();
tx.replace(R.id.content_frame,Fragment.instantiate(MainActivity.this, fragments[0]));
tx.commit();
}
});
}
}
Make a base activity class and put all your drawer code there, and extend this base class for your 3 activity, in that way, you'll have drawer for your all activities.
class Gold extends BaseActivity{
}
For the clicking part, you already set an item click listener, just make a switch case such as
switch (pos){
case 0:
Intent i = new Intent(this,Gold.java);
startActivity(i);
break;
}
// fill the rest
}

Navigation Drawer to switch activities instead of fragments

Is it possible to use a navigation drawer in android but instead of updating fragments, i would like to switch between activities as my means of navigation within the app.
Yes it is possible - it's what I did for my app. I already had a number of activities set up, and rather than convert them all to fragments, I wanted to tailor the navigation drawer to work across all of them. Unfortunately, it's not a quick workaround, so if you have the option of using fragments, I would go with that. But regardless here's how I did it:
Let's say I have 2 activities, both of which I want to have the Navigation Drawer. In the layout.xml for each, I specified a DrawerLayout with the appropriate ListView to hold my navigation options. Essentially, the Navigation drawer is made every time I switch between activities, giving the appearance that it is persisting. To make life a lot easier, I took the common methods required to set up the navigation drawer and put them in their own class: NavigationDrawerSetup.java. That way my activities can use the same custom adapter, etc.
Within this NavigationDrawerSetup.java class, I have the following:
configureDrawer() - this sets up the ActionBar,
ActionBarDrawerToggle, and the required listeners
My custom array adapter (to populate the navigation options within the list)
The selectOptions() method, which handles drawer item clicks
When you set up the navigation drawer within one of your activities, you just create a new NavigationDrawerSetup object and pass in the required layout parameters (like the DrawerLayout, ListView etc). Then you'd call configureDrawer():
navigationDrawer = new NavigationDrawerSetup(mDrawerView, mDrawerLayout,
mDrawerList, actionBar, mNavOptions, currentActivity);
navigationDrawer.configureDrawer();
currentActivity is passed in since the navigation drawer is tied to the activity you are on. You will have to use it when you set up the ActionBarDrawerToggle:
mDrawerToggle = new ActionBarDrawerToggle(currentActivity, // host Activity
mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
R.string.drawer_open, /* "open drawer" description for accessibility */
R.string.drawer_close /* "close drawer" description for accessibility */
)
You will also need to use currentActivity when setting up your custom Adapter:
As for how to switch between activities via the navigation drawer, you can just set up new intents within your selectItem() method:
private void selectItem(int position) {
// Handle Navigation Options
Intent intent;
switch (position) {
case 0:
intent = new Intent(currentActivity, NewActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
currentActivity.startActivity(intent);
break;
case 1:
// etc.
}
Just make sure that your new Activity also has the navigation drawer setup and it should display.
There are a ton of things you can do to customize this method to your own needs, but this is the general structure of how I did it. Hope this helps!
You need a BaseDrawerActivity which implement the Navigation Drawer then extend the BaseDrawerActivity in each activity you need Navigation Drawer.
First create BaseDrawerActivity.java :
public class BaseDrawerActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener{
DrawerLayout drawerLayout;
Toolbar toolbar;
FrameLayout frameLayout;
NavigationView navigationView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_base_drawer);;
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
frameLayout = (FrameLayout) findViewById(R.id.content_frame);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawerLayout.setDrawerListener(toggle);
toggle.syncState();
navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
#Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
//to prevent current item select over and over
if (item.isChecked()){
drawerLayout.closeDrawer(GravityCompat.START);
return false;
}
if (id == R.id.nav_camera) {
// Handle the camera action
startActivity(new Intent(getApplicationContext(), CameraActivity.class));
} else if (id == R.id.nav_gallery) {
startActivity(new Intent(getApplicationContext(), GalleryActivity.class));
} else if (id == R.id.nav_slideshow) {
startActivity(new Intent(getApplicationContext(), SlideshowActivity.class));
} else if (id == R.id.nav_manage) {
startActivity(new Intent(getApplicationContext(), ManageActivity.class));
} else if (id == R.id.nav_share) {
startActivity(new Intent(getApplicationContext(), ShareActivity.class));
} else if (id == R.id.nav_send) {
startActivity(new Intent(getApplicationContext(), SendActivity.class));
}
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
}
then create activity_base_drawer.xml in res/layout folder:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:openDrawer="start">
<include layout="#layout/app_bar_home"/>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/nav_header_home"
app:menu="#menu/activity_home_drawer" />
</android.support.v4.widget.DrawerLayout>
where #layout/app_bar_home is:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<FrameLayout android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.design.widget.CoordinatorLayout>
Next you enter your Activities that will have Navigation Drawer such as CameraActivity.java :
public class CameraActivity extends BaseDrawerActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLayoutInflater().inflate(R.layout.activity_camera, frameLayout);
/**
* Setting title
*/
setTitle("Camera");
}
#Override
protected void onResume() {
super.onResume();
// to check current activity in the navigation drawer
navigationView.getMenu().getItem(0).setChecked(true);
}
}
Where R.layout.activity_camera is your layout for CameraActivity.java.
Then create other Activity like GalleryActivity.java and so on that will have Navigation Drawer:
public class GalleryActivity extends BaseDrawerActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLayoutInflater().inflate(R.layout.activity_gallery, frameLayout);
// Setting title
setTitle("Gallery");
}
#Override
protected void onResume() {
super.onResume();
navigationView.getMenu().getItem(1).setChecked(true);
}
}
As a little improvement to the solution pointed by #David-Crozier, in order to avoid the overlap of both animations (closing the NavigationDrawer and starting a new activity), you can include a little delay in your method as was done in the iosched app v2014:
private void onNavDrawerItemClicked(final int itemId) {
if (itemId == getSelfNavDrawerItem()) {
mDrawerLayout.closeDrawer(GravityCompat.START);
return;
}
if (isSpecialItem(itemId)) {
goToNavDrawerItem(itemId);
} else {
// launch the target Activity after a short delay, to allow the close animation to play
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
goToNavDrawerItem(itemId);
}
}, NAVDRAWER_LAUNCH_DELAY);
// change the active item on the list so the user can see the item changed
setSelectedNavDrawerItem(itemId);
// fade out the main content
View mainContent = findViewById(R.id.main_content);
if (mainContent != null) {
mainContent.animate().alpha(0).setDuration(MAIN_CONTENT_FADEOUT_DURATION);
}
}
mDrawerLayout.closeDrawer(GravityCompat.START);
}
Here the link for reference: https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/BaseActivity.java
The Fragment manager can be replaced as mentioned in the post:
https://guides.codepath.com/android/fragment-navigation-drawer#alternative-to-fragments
You can inflate a layout instead of using a fragment manager.
In your mobile_navigation file XML.
Add the following.
<activity
android:id="#+id/nav_custom"
android:name="net.larntech.nav.CustomActivity"
android:label="#string/menu_custom"
tools:layout="#layout/activity_custom"
/>
You can find the full tutorial using the link below.
Android Studio Navigation Drawer

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).
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.
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?).
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.
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!
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();
...
#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.
//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.
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.
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. I would not use the DrawerLayout.OnDrawerListener onClose(...) either because those callbacks are so slow to be called.
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).
#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.

Categories

Resources