Navigation Drawer to Switch Activities Instead of Fragments

Navigation Drawer to switch activities instead of fragments

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!

Navigation Drawer to switch between activities

Suppose you have 5 items (from 0 index to 4), each index identifying an Activity of your project. You can create a method selectItem(int position)to know what drawer item has been chosen by user.

public void selectItem(int position) {
Intent intent = null;
switch(position) {
case 0:
intent = new Intent(this, Activity_0.class);
break;
case 1:
intent = new Intent(this, Activity_1.class);
break;

...

case 4:
intent = new Intent(this, Activity_4.class);
break;

default :
intent = new Intent(this, Activity_0.class); // Activity_0 as default
break;
}

startActivity(intent);
}

Finally, add this method to your DrawerItemClickListener :

private class DrawerItemClickListener implements ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
selectItem(position);
drawerLayout.closeDrawer(drawerListView);

}
}

It's easier than using Fragments, I think !!!

Switching between activities and fragments in navigation drawer

Have you tried doing the same thing you did with the optionItems and preventing the code related to the fragment to be executed when starting an Activity:

public class BaseDrawerActivity extends AppCompatActivity  {

private DrawerLayout drawerLayout;
private NavigationView nvDrawer;
private ActionBarDrawerToggle actionBarDrawerToggle;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base_drawer);

drawerLayout = findViewById(R.id.drawer);
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.open, R.string.close);
drawerLayout.addDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();

nvDrawer = findViewById(R.id.nvgView);
// Setup drawer view
setupDrawerContent(nvDrawer);

getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);

//Menu created for cart and search icons
@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, menu);
return super.onCreateOptionsMenu(menu);
//return true;
}

//This method is design only for cart and search icons
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();

if(actionBarDrawerToggle.onOptionsItemSelected(item)){
return true;
} else if (id == R.id.cart) {
Intent intent = new Intent(getApplicationContext(), CartActivity.class);
startActivity(intent);
} else if (id == R.id.search) {
Intent intent = new Intent(getApplicationContext(), SearchActivity.class);
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}

//This method is to set up the drawer content/menu
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
selectDrawerItem(menuItem);
return true;
}
});
}

public void selectDrawerItem(MenuItem menuItem) {
// Here we create a new fragment and specify the fragment to show based on nav item clicked
Fragment fragment = null;
Class fragmentClass;
switch(menuItem.getItemId()) {
case R.id.nav_home:
fragmentClass = HomeFragment.class;
break;
case R.id.nav_cat:
fragmentClass = CatalogFragment.class;
break;
case R.id.nav_logout:
fragmentClass = CatalogFragment.class;
break;

case R.id.nav_login:
Intent intent = new Intent(getApplicationContext(), OtherActivity.class);
startActivity(intent);
break;
case R.id.nav_profile:
Intent intent = new Intent(getApplicationContext(), ProfileActivity.class);
startActivity(intent);
break;
default:
fragmentClass = HomeFragment.class;
}
//Code related to fragment should not execute when choosing to start an Activity
if(fragmentClass != null){
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}

// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flcontent, fragment).addToBackStack("back tag").commit();

// Highlight the selected item has been done by NavigationView
}
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
}

}

Want to move from navigation drawer activity to another screen using fragments to show drawer across all screens

Simply for this task you have to override onNavigationItemSelected method in your Activity, which return id of selected fragment on NavigationDrawer.

Try this,

@Override
public boolean onNavigationItemSelected(MenuItem item) {

//calling the method displayselectedscreen and passing the id of selected menu

displaySelectedFragment(item.getItemId());

return true;
}

Now displaySelectedFragment,

private void displaySelectedScreen(int itemId) {

//creating fragment object
Fragment fragment = null;

//initializing the fragment object which is selected
switch (itemId) {

case R.id.your_fragment_one_id:
fragment = new FragOne();
break;

case R.id.your_fragment_two_id:
fragment = new FragTwo();
break;
}

//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.main_layout_id_which_is_to_be_replace, fragment);
ft.commit();
}

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.your_drawer_layout_id);
drawer.closeDrawer(GravityCompat.START);
}

Edit -- If you want navigate from FragOne to FragTwo. Try this,

Create a method in your Activity,

public void showFragTwo(){

FragmentManager manager = getSupportFragmentManager();
FragTwo frag = new FragTwo();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.your_layout_id_which_is_to_be_replace, frag);
transaction.commit();

}

Then in your FragOne when you want to start FragTwo, call startFragTwo method from Activity as,

((YourActivity)  getActivity()).showFragTwo();

NavigationDrawer with Activities vs. NavigationDrawer with Fragments

I was in similar boat and I used Activities method, that way I have each Activity with group of fragments for a particular nav click on the NavigationView. Obviously I use NavigationView, but managing all those fragments with just one MainActivity is really a painful task.

I rather prefer EachActivity managing their own fragments when we click a nav item. This gives me a better performance, since I do not need to worry about lifecycle of soo many fragments and it's backStack and add/remove/show/hide hell.

I used the following SO Question to cleverly use a BaseActivity implementing NavigationDrawer, and sharing it with all the other Activities. The real magic is it does not duplicate code, or it's not just plain old Inheritance technique.

Here's the link, do check it out

I used this method in two of my project's and it's running very well plus I do not have to deal with fragment management right from the very start.

Multiple activities (not fragments) with a NavigationDrawer. How to show currently selected Activity?

Do not put a nav drawer in every activity, this defeats the purpose of extending the NavDrawerBaseActivity class. Because all your other activities extend this base class they should automatically inherit all its functionality. Hence, only put the drawer in the NavDrawerBaseActivity. Then, in your xml for the drawer you can specify each buttons action like:

<Button
style="@style/drawerBtn"
android:id="@+id/activity1Btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick">

Or simply set an onClick listener on your drawer, something like:

myDrawer.setOnClickListener().........etc

Then in your onClick handler (which is inside the NavDrawerBaseActivity class) you can simply check which button was pressed and open the associated activity, something like:

//remember, if you used the onClickListener you have to use @Override at the top of this function
public void onClick(View item) {

//lets see which button on the drawer was pressed....item is the item that triggered the click
switch (item.getId()) {
case R.id.activity1Btn:
Intent intent1 = new Intent(this, Activity1.class);
startActivity(intent1);
break;
case R.id.activity2Btn:
Intent intent2 = new Intent(this, Activity2.class);
startActivity(intent2);
break;
case R.id.activity3Btn:
Intent intent3 = new Intent(this, Activity3.class);
startActivity(intent3);
break;
}
}

Remember that Activity1, Activity2, Activity3 will have to extend NavDrawerBaseActivity which then either have to extend Activity or extend another class which in turn extends Activity...... and so on and so forth. You can then also set things like mDrawerList.setItemChecked(position, true) in this switch. So in short, make all drawer things happen in this class only and simply "implement" this class by extending it, remember this class contains all functionality that is common across all the "child" classes/activities, they all inherit this behaviour

EDIT:

If you want to highlight the items in your drawer and you must rather use setSelected(true) on your item. You can define custom selection states if you want to by creating a selection style in your drawables folder. You then set this style as the background of your list items example:

<!-- drawable/myStyles.xml-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:state_pressed="true" android:drawable="@color/blue"/> <!--item selected state-->
<item android:state_enabled="true" android:state_focused="true" android:drawable="@color/blue"/> <!--item selected state-->
<item android:state_enabled="true" android:state_selected="true" android:drawable="@color/blue"/> <!--item selected state-->
<item android:state_focused="false" android:state_pressed="false" android:drawable="@color/gray"/> <!--item NOT selected state-->
</selector>

and your drawer item:

<LinearLayout
android:id="@+id/my_drawer_item"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:background="@drawable/myStyles">

Then in your switch/if-else statement you set the selected item as myNewSelectedView.setSelected(true). You might have to manually deselect the old one like myOldSelectedItem.setSelected(false)

Then click/selected listener where you have you switch/if-else statement:

 @Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
view.setSelected(true)

//....the rest of your code here
}

Lastly I recommend you try this first as this will be the easiest route to follow if you use a normal listView:

<ListView android:id="@+id/my_list"
android:choiceMode="singleChoice"
android:listSelector="@android:color/blue" />

EDIT2:

Now to retain the selected items state...So it seems that each action on the drawer reinstantiates the base class which isnt ideal. We need to somehow retain the instance state so it acts almost as a singleton. I've tried overriding the the onSaveInstanceState and using the singleInstance launcher state but they did not work. So, for the interim I've come up with the solution of saving the current selection in memory as a static variable:

private static int mCurrentSelectionIndex = 0; //this is defined at the top of your class with your default selected screen ie the first item in the list.

//then in setContentView after assigning the drawer layout you set the currentSelection
@Override
public void setContentView(final int layoutResID) {
//...... first assign the layouts ie mDrawerList = findViewByLayout(R.id.myDrawerList) etc

mDrawerList.setSelection(mCurrentSelectionIndex);
// OR:
mDrawerList.setItemChecked(mCurrentSelectionIndex, true);
}

//then in onClick()
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mCurrentSelection = position;
item.setSelected(true);
}


Related Topics



Leave a reply



Submit