Both the NavigationDrawer and NavigationTabs are great for allowing a user to navigate your app. There are times that you may need to use them in conjunction and possible. However, you can not use the ActionBar Navigation Drawer and ActionBar Navigation Tabs together. In order to use tabs, you must implement them manually in your fagments.
NavigationDrawer
Google has documented how to implement the NavigationDrawer here. Download the sample application found on the documentation page because there are some files that you will need:
- res/drawable/xhdpi/ic_drawer.png
- res/drawable/xhdpi/drawer_shadow.9.png
- res/values/values/strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">DrawerNavigationTabs</string> <string name="action_settings">Settings</string> <string name="hello_world">Hello world!</string> <string-array name="drawer_titles"> <item>Tabs</item> <item>WebView</item> </string-array> <string name="drawer_open">Open navigation drawer</string> <string name="drawer_close">Close navigation drawer</string> <string name="title_section1">Section 1</string> <string name="title_section2">Section 2</string> <string name="title_section3">Section 3</string> </resources>
<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. --> <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"> <!-- As the main content view, the view below consumes the entire space available using match_parent in both dimensions. --> <FrameLayout android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- android:layout_gravity="start" tells DrawerLayout to treat this as a sliding drawer on the left side for left-to-right languages and on the right side for right-to-left languages. The drawer is given a fixed width in dp and extends the full height of the container. A solid background is used for contrast with the content view. --> <ListView android:id="@+id/left_drawer" 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>
Most of the time, a ListView will be enough to accomplish what you want to display in the drawer.
package com.paulusworld.drawernavigationtabs; import android.os.Bundle; import android.content.res.Configuration; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.app.FragmentActivity; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ListView; public class MainActivity extends FragmentActivity { private static final String TAG = MainActivity.class.getSimpleName(); private DrawerLayout mDrawerLayout; private ListView mDrawerList; private ActionBarDrawerToggle mDrawerToggle; private CharSequence mDrawerTitle; private CharSequence mTitle; private String[] mDrawerItmes; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTitle = mDrawerTitle = getTitle(); mDrawerItmes = getResources().getStringArray(R.array.drawer_titles); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerList = (ListView) findViewById(R.id.left_drawer); // set a custom shadow that overlays the main content when the drawer opens mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); // Add items to the ListView mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, mDrawerItmes)); // Set the OnItemClickListener so something happens when a // user clicks on an item. mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); // Enable ActionBar app icon to behave as action to toggle the NavigationDrawer getActionBar().setDisplayHomeAsUpEnabled(true); getActionBar().setHomeButtonEnabled(true); mDrawerToggle = new ActionBarDrawerToggle( this, mDrawerLayout, R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close ) { public void onDrawerClosed(View view) { getActionBar().setTitle(mTitle); invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu } public void onDrawerOpened(View drawerView) { getActionBar().setTitle(mDrawerTitle); invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu } }; mDrawerLayout.setDrawerListener(mDrawerToggle); // Set the default content area to item 0 // when the app opens for the first time if(savedInstanceState == null) { navigateTo(0); } } /* * If you do not have any menus, you still need this function * in order to open or close the NavigationDrawer when the user * clicking the ActionBar app icon. */ @Override public boolean onOptionsItemSelected(MenuItem item) { if(mDrawerToggle.onOptionsItemSelected(item)) { return true; } return super.onOptionsItemSelected(item); } /* * When using the ActionBarDrawerToggle, you must call it during onPostCreate() * and onConfigurationChanged() */ @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawerToggle.onConfigurationChanged(newConfig); } private class DrawerItemClickListener implements OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { navigateTo(position); } } private void navigateTo(int position) { switch(position) { case 0: getSupportFragmentManager() .beginTransaction() .replace(R.id.content_frame, TabbedFragment.newInstance(), TabbedFragment.TAG).commit(); break; case 1: getSupportFragmentManager() .beginTransaction() .replace(R.id.content_frame, WebViewFragment.newInstance(), WebViewFragment.TAG).commit(); break; } mDrawerLayout.closeDrawer(mDrawerList); } @Override public void setTitle(CharSequence title) { mTitle = title; getActionBar().setTitle(mTitle); } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <WebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
package com.paulusworld.drawernavigationtabs; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.webkit.WebView; public class WebViewFragment extends Fragment { public final static String TAG = WebViewFragment.class.getSimpleName(); public WebViewFragment() { // TODO Auto-generated constructor stub } public static WebViewFragment newInstance() { return new WebViewFragment(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_webview, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); WebView webView = (WebView) view.findViewById(R.id.webView); webView.loadUrl("http://www.paulusworld.com"); } }
The easiest way to accomplish adding a tabbed activity or fragment in this case, is to create a new activity and selecting the type of navigation you want. In this case, I've chosen Scrollable Tabs + Swipe. Once the activity was created, I had to modify from a FragmentActivity to a Fragment:
- Remove the <activity> tag for the newly added Activity in the AndroidManifest.xml file
- Change the onCreate() function to what you see here.
- Add the onCreateView() function
- Updated the names to classes and layouts.
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".TabbedFragment" > <!-- This title strip will display the currently visible page title, as well as the page titles for adjacent pages. --> <android.support.v4.view.PagerTitleStrip android:id="@+id/pager_title_strip" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:background="#33b5e5" android:paddingBottom="4dp" android:paddingTop="4dp" android:textColor="#fff" /> </android.support.v4.view.ViewPager>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".TabbedActivity$DummySectionFragment" > <TextView android:id="@+id/section_label" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
package com.paulusworld.drawernavigationtabs; import java.util.Locale; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class TabbedFragment extends Fragment { public static final String TAG = TabbedFragment.class.getSimpleName(); SectionsPagerAdapter mSectionsPagerAdapter; ViewPager mViewPager; public static TabbedFragment newInstance() { return new TabbedFragment(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_tabbed, container, false); mSectionsPagerAdapter = new SectionsPagerAdapter( getChildFragmentManager()); mViewPager = (ViewPager) v.findViewById(R.id.pager); mViewPager.setAdapter(mSectionsPagerAdapter); return v; } public class SectionsPagerAdapter extends FragmentPagerAdapter { public SectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { Fragment fragment = new TabbedContentFragment(); Bundle args = new Bundle(); args.putInt(TabbedContentFragment.ARG_SECTION_NUMBER, position + 1); fragment.setArguments(args); return fragment; } @Override public int getCount() { return 3; } @Override public CharSequence getPageTitle(int position) { Locale l = Locale.getDefault(); switch (position) { case 0: return getString(R.string.title_section1).toUpperCase(l); case 1: return getString(R.string.title_section2).toUpperCase(l); case 2: return getString(R.string.title_section3).toUpperCase(l); } return null; } } public static class TabbedContentFragment extends Fragment { public static final String ARG_SECTION_NUMBER = "section_number"; public TabbedContentFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_tabbed_content, container, false); TextView dummyTextView = (TextView) rootView .findViewById(R.id.section_label); dummyTextView.setText(Integer.toString(getArguments().getInt( ARG_SECTION_NUMBER))); return rootView; } } }