Android開發(37) 使用DrawerLayout實現抽屜式導航菜單
- 2020 年 3 月 16 日
- 筆記
概述
最近流行 左側抽屜式的導航條菜單,知乎,360,QQ都使用了這樣的導航菜單,我們也了解下:
Android Design 的流行趨勢:Navigation Drawer 導航抽屜 參考這篇文章:http://www.geekpark.net/topics/183724
效果圖:


特點
1.標題欄(或者actionBar) 做的有個 菜單圖標按鈕(三條線或者其他)。一般這樣的標題欄左側和右側都會有圖標按鈕。如圖1所示。
2.點擊圖標按鈕 從左側向右 慢慢退出一個 菜單視圖(View),遮蓋在 內容頁(首頁)的視圖上,同時,產生遮蓋層。如圖2所示。
實
官方示例
參考自谷歌開發者網站的示例,在這個頁面可以下載到示例。http://developer.android.com/training/implementing-navigation/nav-drawer.html
引用類庫
需要android-support-v4.jar
主要控件
谷歌提供的抽屜控件: android.support.v4.widget.DrawerLayout
參考這片文章的解釋:http://blog.csdn.net/xiahao86/article/details/8995827
具體實現
首頁(比如叫:MainActivity)內容布局,寫一個 android.support.v4.widget.DrawerLayout,它需要包含兩個內容視圖元素,第一個視圖元素是 主顯示內容頁,第二個是要抽屜彈出的視圖。
<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. --> <zyf.demo.navigationdrawer.NavigationMenu android:id="@+id/navigation_menu" android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" > </zyf.demo.navigationdrawer.NavigationMenu> </android.support.v4.widget.DrawerLayout>
我在這裡寫了個自定義控件 「 zyf.demo.navigationdrawer.NavigationMenu " , 注意它的 android:layout_gravity="start" ,是 start 不是left。
MainActivity需要 為DrawerLayout 註冊一個回調事件接口ActionBarDrawerToggle ,這個事件的實現者監聽器會獲得 抽屜彈出(onDrawerOpened)和關閉(onDrawerClosed)的事件。
MainActivity 的代碼
package zyf.demo.navigationdrawer; import android.os.Bundle; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.content.res.Configuration; import android.graphics.drawable.ColorDrawable; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.widget.DrawerLayout; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity { private NavigationMenu mNavigationMenu; private DrawerLayout mDrawerLayout; private ActionBarDrawerToggle mDrawerToggle; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 獲得抽屜控件 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); // 獲得菜單控件 mNavigationMenu = (NavigationMenu) findViewById(R.id.navigation_menu); mNavigationMenu.attacthDrawer(mDrawerLayout); // enable ActionBar app icon to behave as action to toggle nav // drawer getActionBar().setDisplayHomeAsUpEnabled(true); // 使actionbar 的logo圖標透明不可見 getActionBar().setIcon( new ColorDrawable(getResources().getColor( android.R.color.transparent))); // 註冊導航菜單抽屜 的彈出和關閉事件 mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */ mDrawerLayout, /* DrawerLayout object */ R.drawable.ic_notification_content, /* * 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 */ ) { // 當導航菜單抽屜 關閉後 public void onDrawerClosed(View view) { // 顯示當前內容頁的標題 getActionBar().setTitle(getTitle()); invalidateOptionsMenu(); // creates call to // onPrepareOptionsMenu() } // 當導航菜單抽屜 打開後 public void onDrawerOpened(View drawerView) { // 顯示導航菜單的標題 getActionBar().setTitle(mNavigationMenu.getTitle()); invalidateOptionsMenu(); // creates call to // onPrepareOptionsMenu() } }; mDrawerLayout.setDrawerListener(mDrawerToggle); // 顯示首頁的內容 showFragment(new HomeFragment()); // 當更換主頁內的 子頁面(fragment)時,隱藏導航菜單 mNavigationMenu.hide(); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); } /* Called whenever we call invalidateOptionsMenu() */ @Override public boolean onPrepareOptionsMenu(Menu menu) { // If the nav drawer is open, hide action items related to the content // view // 當彈出導航菜單時,使 actionbar的擴展按鈕不可見 boolean drawerOpen = mDrawerLayout.isDrawerOpen(mNavigationMenu); menu.findItem(R.id.action_websearch).setVisible(!drawerOpen); return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // The action bar home/up action should open or close the drawer. // ActionBarDrawerToggle will take care of this. if (mDrawerToggle.onOptionsItemSelected(item)) { return true; } // Handle action buttons switch (item.getItemId()) { case R.id.action_websearch: Toast.makeText(this, "你點擊了搜索按鈕", Toast.LENGTH_LONG).show(); return true; default: return super.onOptionsItemSelected(item); } } private void showFragment(Fragment fragment) { FragmentManager fragmentManager = getFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.content_frame, fragment).commit(); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); // Sync the toggle state after onRestoreInstanceState has occurred. mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Pass any configuration change to the drawer toggls mDrawerToggle.onConfigurationChanged(newConfig); } }
下面給出我寫的自定義控件的實現:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/listView1" android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" android:choiceMode="singleChoice" android:background="#FFFFFF"/> </RelativeLayout>
代碼 package zyf.demo.navigationdrawer;
import android.content.Context; import android.support.v4.widget.DrawerLayout; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Toast; public class NavigationMenu extends RelativeLayout { LayoutInflater mLayoutInflater; ListView mlistView1; String[] menuItemsDataSource; private DrawerLayout mDrawerLayout;// 關聯到的抽屜控件 public NavigationMenu(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initLayout(context); } public NavigationMenu(Context context, AttributeSet attrs) { super(context, attrs); initLayout(context); } public NavigationMenu(Context context) { super(context); initLayout(context); } private void initLayout(Context context) { mLayoutInflater = LayoutInflater.from(context); View contentView = mLayoutInflater.inflate(R.layout.navigation_menu, null); RelativeLayout.LayoutParams lp = new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); this.addView(contentView, lp); mlistView1 = (ListView) contentView.findViewById(R.id.listView1); menuItemsDataSource = getResources().getStringArray( R.array.navigation_menu_items_array); mlistView1.setAdapter(new ArrayAdapter<String>(context, R.layout.navaigation_menu_list_view_item, menuItemsDataSource)); mlistView1.setOnItemClickListener(new DrawerItemClickListener()); } /** * 包含 的 listView的點擊事件 * @author yunfei * */ private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // selectItem(position); mlistView1.setItemChecked(position, true); hide(); Toast.makeText(getContext(), "你選擇了" + position, 0).show(); } } public CharSequence getTitle() { return "導航菜單"; } /** * 關聯到 drawerLayout * @param drawerLayout */ public void attacthDrawer(DrawerLayout drawerLayout) { mDrawerLayout = drawerLayout; } /** * 隱藏 */ public void hide() { if (mDrawerLayout != null) mDrawerLayout.closeDrawer(NavigationMenu.this); } /** * 出現 */ public void show() { if (mDrawerLayout != null) mDrawerLayout.openDrawer(NavigationMenu.this); } }
代碼下載:
http://yunpan.cn/cggiDkFNCp2Jw 訪問密碼 c3ed
參考:
http://blog.csdn.net/xiahao86/article/details/8995827 http://developer.android.com/training/implementing-navigation/nav-drawer.html http://www.geekpark.net/topics/183724