源碼地址:https://github.com/licong/android-menudrawer
MenuDrawer ——簡單的使用方法
今天,我們需要達到的效果是,使用MenuDrawer創建一個側滑菜單視圖,當我們點擊菜單項(使用ListView)時,右面的內容視圖(就是一個TextView)會響應這個點擊事件
默認是菜單項隱藏在左邊,當從左邊緣滑動時,菜單視圖出現,回滑時,菜單隱藏
先看看效果圖吧:
【用到的 MenuDrawer API】
1、將MenuDrawer綁定到當前的Activity中,並返回MenuDrawer對象
這幾個方法是靜態方法,是創建MenuDrawer對象的方法,注意:MenuDrawer沒有構造方法
MenuDrawer.attach(Activity activity )
MenuDrawer.attach(Activity activity , int dragMode) 參數dragMode指定MenuDrawer的菜單視圖的加載模式
MenuDrawer.attach(Activity activity, Position position) 參數position指定菜單視圖加載在屏幕的哪一邊:上下左右,本實例是加載在左邊,默認也是在左邊
MenuDrawer.attch(Activity activity, int dragMode, Position position)
MenuDrawer.attch(Activity activity, int dragMode, Position position, boolean attachStatic) 最后一個參數明顯是:是否靜態的顯示一個Menu視圖,即菜單不能夠滑動
dragMode指定MenuDrawer的菜單視圖的加載模式,總共有兩種加載方式:
普通內容視圖模式:MenuDrawer.MENU_DRAG_CONTENT,效果如下:
填充窗口模式:MenuDrawer.MENU_DRAG_WINDOW,效果如下:
2、向MenuDrawer中添加內容視圖
setContentView(int layoutResId) 通過布局文件的ID加載
setContentView(View view) 直接通過View加載
setContentView(View view, LayoutParams params)
3、向MenuDrawer中添加菜單視圖 (一般是加載ListView)
setMenuView(int layoutResId)
setMenuView(View view)
setMenuView(View view, LayoutParams params)
4、向當前的選中項中添加 "指針" 用來標定當前的活動項
setActiveView(View view, int position)
參數 View : 當前的菜單項對應的View
參數position: 當前View在adapter中的位置
注意:想要在程序中使用“指針”的功能的話,應該有三步:
①在Manifest.xml文件中為當前的Activity配置主題含有“指針”圖片的Theme主題
②在Adapter的getView()方法中調用setTag(R.id.mdActiveViewPosition, position)方法
③調用上面的setActiveView()方法
一會兒通過下面的例子,就會秒懂了!一切盡在掌握之中
5、關閉選項菜單/打開選項菜單
closeMenu();
closeMenu(boolean animate); 是否使用動畫,但是和上面的方法在效果上基本沒有什么分別
toggleMenu(); 這個是一個開關選項,當菜單視圖處於打開模式時,調用這個方法,那么菜單視圖就會關閉,反之,菜單就會打開
6、返回當前的菜單視圖的狀態
int getDrawerState()
比如正在展開、正在關閉、已經展開、已經關閉等等
7、設置菜單視圖的大小
setMenuSize(int size)
我們亦可以在style文件中更改這個屬性,一會兒你就秒懂了
8、重新繪制當前的MenuDrawer對象
invalidate()
9、自動開啟菜單視圖
peekDrawer();
這個方法並不是將菜單視圖整個顯示出來,而是講菜單視圖輕輕的抻出一小條,這樣為的是能夠讓用戶發現在左邊隱藏着一個菜單視圖,這個方法一般放在Activity的onCreate()方法中,並且一般只使用一次
【實例代碼】
主布局文件 MenuTuiCoolActivity.java 文件
1 package com.penglee.tuicool; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import android.app.Activity; 6 import android.os.Build; 7 import android.os.Bundle; 8 import android.view.MenuItem; 9 import android.view.View; 10 import android.view.ViewGroup; 11 import android.widget.AbsListView; 12 import android.widget.AdapterView; 13 import android.widget.BaseAdapter; 14 import android.widget.ListView; 15 import android.widget.TextView; 16 17 18 import net.simonvt.menudrawer.*; 19 20 public class MenuTuicoolActivity extends Activity { 21 22 //定義菜單適配器 23 private MenuAdapter menuAdapter ; 24 25 //定義ListView菜單 26 ListView menuList ; 27 28 //保存當前的活動菜單項 29 int currentActiveItem = -1 ; 30 31 //定義內容視圖 32 TextView contentText ; 33 34 //定義MenuDrawer對象 35 private MenuDrawer menuDrawer ; 36 37 @Override 38 protected void onCreate(Bundle savedInstanceState) { 39 super.onCreate(savedInstanceState); 40 41 //創建MenuDrawer,並設定加載模式 42 menuDrawer = MenuDrawer.attach(this, MenuDrawer.MENU_DRAG_CONTENT); 43 44 //創建菜單視圖 45 menuList= new ListView(this) ; 46 menuAdapter = new MenuTuicoolActivity.MenuAdapter() ; 47 menuList.setAdapter(menuAdapter); 48 49 //為菜單視圖添加事件響應 50 menuList.setOnItemClickListener(mItemClickListener); 51 menuList.setOnScrollListener(new AbsListView.OnScrollListener() { 52 @Override 53 public void onScrollStateChanged(AbsListView view, int scrollState) { 54 } 55 56 @Override 57 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 58 /*為什么要進行重繪呢?因為我們為菜單項設置了一個指示及“指針” 59 * 如果我們不重繪的話,那么當滾動菜單欄的時候,那個“指針”就不會移動 60 * 也就是說,那個指針不會隨着當前的那個活動的菜單項上下移動 61 * 此外還要注意的一點是,這個方法必須在 62 * menuDrawer = MenuDrawer.attach(this, MenuDrawer.MENU_DRAG_CONTENT); 63 * 之后調用,因為在menuDrawer還沒有創建之前,是不能夠調用這個方法的,否則會拋出 64 * NullPointException**/ 65 menuDrawer.invalidate(); 66 } 67 }); 68 69 //創建內容視圖 70 contentText = new TextView(this) ; 71 //contentText.setBackgroundResource(R.drawable.img_frame_background); 72 73 //加載菜單視圖和內容視圖 74 menuDrawer.setMenuView(menuList); 75 menuDrawer.setContentView(contentText); 76
//Animates the drawer slightly open until the user opens the drawer.
menuDrawer.peekDrawer();
77 //設置ActionBar中的程序圖標可見,並且顯示那個向左的指示箭頭標志 78 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 79 getActionBar().setDisplayHomeAsUpEnabled(true); 80 } 81 82 } 83 84 85 86 //定義菜單視圖的菜單項的監聽器 87 private AdapterView.OnItemClickListener mItemClickListener = new AdapterView.OnItemClickListener() { 88 @Override 89 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 90 91 //當前的活動菜單項為position 92 currentActiveItem = position ; 93 94 //為當前的活動項添加“指針” 95 menuDrawer.setActiveView(view, position); 96 97 //改變contentText中的內容 98 contentText.setText(((TuiCool_MenuItem)(menuAdapter.getItem(position))).getMenuText()) ; 99 100 101 //關閉菜單視圖 102 menuDrawer.closeMenu(true); 103 } 104 }; 105 106 107 108 //《當用戶按下了"手機上的返回功能按鍵"的時候會回調這個方法》 109 @Override 110 public void onBackPressed() { 111 final int drawerState = menuDrawer.getDrawerState(); 112 if (drawerState == MenuDrawer.STATE_OPEN || drawerState == MenuDrawer.STATE_OPENING) { 113 menuDrawer.closeMenu(); 114 return; 115 } 116 //也就是說,當按下返回功能鍵的時候,不是直接對Activity進行彈棧,而是先將菜單視圖關閉 117 super.onBackPressed(); 118 } 119 120 @Override 121 public boolean onOptionsItemSelected(MenuItem item) { 122 switch (item.getItemId()) { 123 case android.R.id.home: // 當單擊了程序圖標的位置時返回android.R.id.home 124 //一次點擊菜單視圖打開,再一次單擊則關閉菜單視圖 125 menuDrawer.toggleMenu(); 126 return true; 127 } 128 129 return super.onOptionsItemSelected(item); 130 } 131 132 //定義菜單分隔條類 133 private static class Category { 134 String mTitle; 135 Category(String title) { 136 mTitle = title; 137 } 138 } 139 140 //定義菜單項類 141 private static class TuiCool_MenuItem{ 142 143 private String menuText ; 144 private int menuIcon ; 145 146 public TuiCool_MenuItem(String menuText , int menuIcon){ 147 this.menuText=menuText ; 148 this.menuIcon=menuIcon ; 149 } 150 151 public String getMenuText(){ 152 return this.menuText ; 153 } 154 155 public int getMenuIcon(){ 156 return this.menuIcon ; 157 } 158 } 159 160 //定義自定義菜單項組Adapter 161 private class MenuAdapter extends BaseAdapter{ 162 163 //用來存貯菜單項和菜單分隔條對象 164 private List<Object> menuItems = new ArrayList<Object>() ; 165 166 //加載所有的菜單項和菜單分隔條 167 public MenuAdapter(){ 168 169 menuItems.add(new Category("分組一")) ; 170 menuItems.add(new TuiCool_MenuItem("離線",R.drawable.img_1)) ; 171 menuItems.add(new TuiCool_MenuItem("站點",R.drawable.img_2)); 172 173 menuItems.add(new Category("分組二")); 174 menuItems.add(new TuiCool_MenuItem("搜索",R.drawable.img_3)) ; 175 menuItems.add(new TuiCool_MenuItem("發現",R.drawable.img_4)) ; 176 menuItems.add(new TuiCool_MenuItem("設置",R.drawable.img_5)) ; 177 } 178 179 @Override 180 public int getCount() { 181 return menuItems.size(); 182 } 183 184 @Override 185 public Object getItem(int position) { 186 return menuItems.get(position); 187 } 188 189 @Override 190 public long getItemId(int position) { 191 return position; 192 } 193 194 /*這個方法和下面的一個方法只是用於標定你所創建的菜單中有幾種類型的項目, 195 *一般來說就有兩種,一種是分隔條項目、一種是實際的可選項目,這兩個方法不會自動回調 196 *只是為讓程序員在getView()等方法中能夠方便使用這兩個方法來判定當前的項目的類型 197 **/ 198 public int getItemViewType(int position) { 199 return getItem(position) instanceof TuiCool_MenuItem ? 0 : 1; 200 } 201 202 @Override 203 public int getViewTypeCount() { 204 return 2; 205 } 206 207 //當前的對象對應的組件是否能夠被選中或者被點擊,即菜單項對象能夠被點擊,分隔條對象不能夠被點擊 208 @Override 209 public boolean isEnabled(int position) { 210 return getItem(position) instanceof TuiCool_MenuItem; 211 } 212 213 //指明Adapter中的所有的對象對應的組件是否都能夠被點擊 214 @Override 215 public boolean areAllItemsEnabled() { 216 return false; 217 } 218 219 @Override 220 public View getView(int position, View convertView, ViewGroup parent) { 221 222 View view = convertView ; 223 Object item = menuItems.get(position) ; 224 225 if(item instanceof TuiCool_MenuItem){ 226 if(view == null){ 227 view =getLayoutInflater().inflate(R.layout.menu_tuicool, parent, false); 228 } 229 ((TextView) view).setText(((TuiCool_MenuItem)item).getMenuText()); 230 ((TextView) view).setCompoundDrawablesWithIntrinsicBounds( 231 ((TuiCool_MenuItem)item).getMenuIcon(), 0, 0, 0); 232 }else{ 233 view = getLayoutInflater().inflate(R.layout.category_style, parent, false); 234 ((TextView) view).setText(((Category)item).mTitle); 235 } 236 237 //為每個view添加Tag 238 view.setTag(R.id.mdActiveViewPosition, position); 239 240 if (position == currentActiveItem) { 241 menuDrawer.setActiveView(view, position); 242 } 243 /*當我們將MenuDrawer庫加入到當前工程中后,R文件中會自動生成上面的R.id.mdActivity 244 *在調用setActiveView()方法之前,必須得為每個view指定Tag, 245 *並且第一個參數屬性值必須為R.id.mdActiveViewPosition 246 *既然我們已經在菜單的監聽器中為當前活動的菜單項添加了“指針”為什么還要添加呢? 247 *因為,我們在監聽方法中將菜單關閉了,當在一次顯示菜單視圖時,會進行重繪 248 *即重新調用這個getview()方法,所以我們要重新設定一下這個“指針”**/ 249 return view; 250 } 251 } 252 }
菜單分隔條布局文件 category_style.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <TextView xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 style="@style/category_style"> 6 </TextView>
菜單項布局文件 menu_tuicool.xml
1 <TextView 2 xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" 5 style="@style/item_style"/>
styles.xml文件
1 <resources> 2 3 <!-- 4 Base application theme, dependent on API level. This theme is replaced 5 by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 6 --> 7 <style name="AppBaseTheme" parent="android:Theme.Light"> 8 <!-- 9 Theme customizations available in newer API levels can go in 10 res/values-vXX/styles.xml, while customizations related to 11 backward-compatibility can go here. 12 --> 13 </style> 14 15 <!-- Application theme. --> 16 <style name="AppTheme" parent="AppBaseTheme"> 17 <!-- All customizations that are NOT specific to a particular API-level can go here. --> 18 </style> 19 20 <!-- 為菜單項設置style --> 21 <style name="item_style"> 22 <item name="android:background">@drawable/md__list_selector_disabled_holo_dark</item> 23 <item name="android:textAppearance">?android:attr/textAppearance</item> 24 <item name="android:textColor">?android:attr/textColorPrimaryInverse</item> 25 <item name="android:textSize">18sp</item> 26 <item name="android:paddingLeft">16dp</item> 27 <item name="android:paddingRight">32dp</item> 28 <item name="android:paddingTop">8dp</item> 29 <item name="android:paddingBottom">8dp</item> 30 <item name="android:drawablePadding">16dp</item> 31 <item name="android:gravity">center_vertical</item> 32 </style> 33 34 <!-- 為分隔條設置style --> 35 <style name="category_style"> 36 <item name="android:textStyle">bold</item> 37 <item name="android:textColor">?android:attr/textColorSecondaryInverse</item> 38 <item name="android:textSize">14sp</item> 39 <item name="android:textAllCaps">true</item> 40 41 <item name="android:gravity">center_vertical</item> 42 <item name="android:paddingLeft">16dp</item> 43 <item name="android:background">@drawable/md__category_background</item> 44 45 <item name="android:singleLine">true</item> 46 <item name="android:ellipsize">end</item> 47 </style> 48 49 <!-- 為“左側菜單”的“指針和寬度”設置style,在設置當前的activity的theme時要用 -->
注意這里面的Widget.MenuDrawer、mdActiveIndicator、mdMenuSize字段都是MenuDrawer庫中定義好的字段屬性,我們只管直接用就行了 50 <style name="MenuDrawerStyle.Left" parent="Widget.MenuDrawer"> 但是 MenuDrawerStyle.Left 這個名字可以自己取
51 <item name="mdActiveIndicator">@drawable/menu_arrow</item> 這張圖就是效果中那個小的“指針”圖片 52 <item name="mdMenuSize">250dp</item> 顯然通過這個屬性就能夠更改菜單視圖的寬度 53 </style> 54 </resources>
themes.xml文件
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 <style name="SampleTheme" parent="@android:style/Theme.Holo.Light"> SampleTheme這個明智可以自己取 4 <item name="menuDrawerStyle">@style/MenuDrawerStyle.Left</item> menuDrawerStyle這個字段是MenuDrawer自定義的屬性,只管用就好 5 </style> 6 7 </resources>
Manifest.xml配置文件
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.penglee.tuicool" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk 8 android:minSdkVersion="17" 9 android:targetSdkVersion="17" /> 10 11 <application 12 android:allowBackup="true" 13 android:icon="@drawable/ic_launcher" 14 android:label="@string/app_name" 15 android:theme="@style/AppTheme"> 16 <activity 17 android:name=".MenuTuicoolActivity" 18 android:label="@string/app_name" 19 android:theme="@style/SampleTheme"> 這樣就能夠使用“指針”功能了 20 <intent-filter> 21 <action android:name="android.intent.action.MAIN" /> 22 23 <category android:name="android.intent.category.LAUNCHER" /> 24 </intent-filter> 25 </activity> 26 </application> 27 28 </manifest>
【文檔結構】
【分析】
雖然我們在內容視圖部分使用的是一個TextView,在菜單視圖中使用的是一個ListView,但是setContentView(View view)、setMenuView(View view)方法中並沒有限制,你想所有的布局容器,如LinearLayout等,都是View 組件,我們可以以布局組件為View容器,之后可在里面添加任何的東西,甚至是Fragment,之后我們使用inflate方法將這個布局文件轉化成View,裝入MenuDrawer中,一切東西就都有了
正個項目文件源碼在郵箱——名字叫做TuiCool