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