Android——自帶側滑菜單DrawerLayout的使用方法
DrawerLayout介紹
1、在Android的support庫中增加了一個專門用於創建側滑菜單的組件DrawerLayout,接下來我們就講解一下怎樣使用這個原生的組件創建一個仿推酷的應用
2、先來看看使用DrawerLayout的步驟:
①在佈局文件中添加<android.support.v4.widget.DrawerLayout> 根元素
②在這個根元素中首先添加一個 內容視圖組件,比如:我們添加一個容器
③再在這個根元素中添加側滑菜單視圖組件,一般來說就是一個ListView組件
④爲ListView設定Adapter,和點擊事件監聽器
⑤爲DrawerLayout添加 開、關 狀態監聽器
3、只要遵循上面的幾步就能夠完成一個側滑菜單的創建,非常的簡單,下面我們就通過模仿推酷客戶端,一步一步的說明怎樣創建側滑菜單
效果示例圖
功能描述
1、打開應用的時候,主界面如圖1,ActionBar沒有顯示應用圖標,只顯示“推酷”兩個字
2、ActionBar右邊有一個綠色的圖標是一個action菜單,當我們打開側滑菜單的時候這個菜單圖標就會隱藏,如圖1
3、當我們點擊了側滑菜單中的某項時,ActionBar中的標題內容顯示爲當前選中的項目的標題
4、同時,如果我們已經選中了某一項,達到了圖3所示的狀態,這時我們在打開側滑菜單,這時ActionBar中的標題內容改爲“推酷”,也就是說,當側滑菜單給關閉的時候,ActionBar中的標題是選中的項目的標題,當側滑菜單處於打開狀態的時候,ActionBar上的標題顯示爲全局的“推酷”,同事那個綠色的action菜單圖標被隱藏
5、當側滑菜單處於打開狀態的時候,如果我麼單擊了手機上的“返回”物理按鍵的話,側滑菜單關閉
創建步驟
步驟一、在主佈局文件中創建DrawerLayout根元素佈局——avtivity_main.xml文件
<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">
<!-- The main content view -->
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/content"/>
<!-- The navigation drawer -->
<ListView android:id="@+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#33333333"
android:dividerHeight="0dp"
android:background="#ffeeeeee"
android:scrollbars="none"/>
</android.support.v4.widget.DrawerLayout>
注意事項:
1、必須指定菜單視圖組件ListView必須指定 android:layout_gravity屬性,當屬性值設爲left的話側滑菜單位於左邊,否則位於右面,由於有的語言是從右到左寫,那麼只要指定屬性值爲 start 的話,android 會自行將側滑菜單放在書寫起始的一邊
2、android:layout_width 指定了側滑菜單的寬度,但是不能夠超過320dp,否則會覆蓋整個視圖,就不好看了
3、必須先放內容視圖的控件,之後放側滑菜單視圖控件
步驟二:創建側滑菜單ListView的Adapter——DrawerAdapter.java
DrawerAdapter.java文件
package com.example.navigaterdrawer;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
/**定義菜單項類*/
class TuiCoolMenuItem {
String menuTitle ;
int menuIcon ;
//構造方法
public TuiCoolMenuItem(String menuTitle , int menuIcon ){
this.menuTitle = menuTitle ;
this.menuIcon = menuIcon ;
}
}
/**自定義設置側滑菜單ListView的Adapter*/
public class DrawerAdapter extends BaseAdapter{
//存儲側滑菜單中的各項的數據
List<TuiCoolMenuItem> MenuItems = new ArrayList<TuiCoolMenuItem>( ) ;
//構造方法中傳過來的activity
Context context ;
//構造方法
public DrawerAdapter( Context context ){
this.context = context ;
MenuItems.add(new TuiCoolMenuItem("", R.drawable.peng)) ;
MenuItems.add(new TuiCoolMenuItem("推薦", R.drawable.advise)) ;
MenuItems.add(new TuiCoolMenuItem("發現", R.drawable.find)) ;
MenuItems.add(new TuiCoolMenuItem("主題", R.drawable.theme)) ;
MenuItems.add(new TuiCoolMenuItem("站點", R.drawable.point)) ;
MenuItems.add(new TuiCoolMenuItem("搜索", R.drawable.search)) ;
MenuItems.add(new TuiCoolMenuItem("離線", R.drawable.leave)) ;
MenuItems.add(new TuiCoolMenuItem("設置", R.drawable.set)) ;
}
@Override
public int getCount() {
return MenuItems.size();
}
@Override
public TuiCoolMenuItem getItem(int position) {
return MenuItems.get(position) ;
}
@Override
public long getItemId(int position) {
return position ;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView ;
if(view == null){
view =LayoutInflater.from(context).inflate(R.layout.menudrawer_item, parent, false);
((TextView) view).setText(getItem(position).menuTitle) ;
((TextView) view).setCompoundDrawablesWithIntrinsicBounds(getItem(position).menuIcon, 0, 0, 0) ;
}
return view ;
}
}
menudrawer_item.xml文件
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/item_style">
</TextView>
styles.xml文件
<resources>
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Light">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
<style name="item_style">
<item name="android:textAppearance">?android:attr/textAppearance</item>
<item name="android:textSize">18sp</item>
<item name="android:paddingLeft">16dp</item>
<item name="android:paddingRight">32dp</item>
<item name="android:paddingTop">10dp</item>
<item name="android:paddingBottom">10dp</item>
<item name="android:drawablePadding">16dp</item>
<item name="android:gravity">center_vertical</item>
</style>
</resources>
步驟三:主Activity文件——MainActivity.java
1、非常明顯的是:接下來我們要爲ListView設定 Adapter 以及 設定點擊事件監聽器,在單擊事件監聽器中我們實現的是:用Fragment來替換FrameLayout
這些都非常的簡單,不再贅述
2、之後,我們就要爲DrawerLayout添加菜單開、關狀態監聽器,爲的是能夠動態的改變ActionBar中的顯示內容,這裏面就要注意一下:
①爲了能夠監聽側滑菜單的開關狀態我們需要調用DrawerLayout的setDrawerListener()方法,之後將實現了DrawerLayout.DrawerListener接口的實例對象當做參數,傳進去,這個DrawerLayout.DrawerListener監聽器中有兩個方法onDrawerOpened()和DrawerClosed(),當側滑菜單開、關時,會回調他們之中的某一個
②如果你監聽側滑菜單的開、關事件,並不是爲了和ActionBar發生關係,是爲了處理其他的事件,那麼使用上面的方法就行了
③如果你監聽側滑菜單的開、關事件,就是爲了和ActionBar發生關係,動態的更改ActionBar的內容,那麼鼓勵使用ActionBarDrawerToggle類 ,這個類繼承了上面的DrawerLayout.DrawerListener接口,所以你依然能夠重寫上面的兩個回調方法,之後調用DrawerLayout的setDrawerListener()方法,與此同時,正如你下面將會看到的那樣:使用ActionBarDrawerToggle類作爲監聽器是因爲:它已經將ActionBar上的應用圖標單擊事件和側滑菜單的開關綁定好了,無需在人爲的進行這方面的邏輯控制;而且使用它能夠非常方便的進行“指示圖標”的更換,只需要在創建這個類的對象的時候,將要使用的圖標作爲構造參數傳進去即可
④當然,一般我們就使用google自帶的默認的“指示圖標”——三橫
⑤需要注意的是:爲了使ActionBarDrawerToggle監聽器能夠適應於Activity的生命週期,我們需要在Activity中的幾個方法中添加一些語句,在下面的程序中我們會提到,非常的簡單
MainActivity.java
package com.example.navigaterdrawer;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends Activity {
ListView menuDrawer ; //側滑菜單視圖
DrawerAdapter menuDrawerAdapter ; // 側滑菜單ListView的Adapter
DrawerLayout mDrawerLayout ; // DrawerLayout組件
//當前的內容視圖下(即側滑菜單關閉狀態下),ActionBar上的標題,
String currentContentTitle ;
ActionBarDrawerToggle mDrawerToggle ; //側滑菜單狀態監聽器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//開始時顯示全局標題“推酷”
currentContentTitle = getResources().getString(R.string.global_title) ;
//爲側滑菜單設置Adapter,併爲ListView添加單擊事件監聽器
menuDrawer = (ListView)findViewById(R.id.left_drawer) ;
menuDrawerAdapter = new DrawerAdapter(this) ;
menuDrawer.setAdapter(menuDrawerAdapter);
menuDrawer.setOnItemClickListener(new DrawerItemClickListener());
//爲DrawerLayout註冊狀態監聽器
mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
mDrawerToggle = new DrawerMenuToggle(
this, mDrawerLayout, R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) ;
mDrawerLayout.setDrawerListener(mDrawerToggle);
//設置ActionBar的指示圖標可見,設置ActionBar上的應用圖標位置處可以被單擊
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
getActionBar().setTitle(currentContentTitle);
//隱藏ActionBar上的應用圖標,只顯示文字label
getActionBar().setDisplayShowHomeEnabled(false);
}
/**側滑菜單單擊事件監聽器*/
private class DrawerItemClickListener implements ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
selectItem(position);
}
public void selectItem(int position){
//爲內容視圖加載新的Fragment
Bundle bd = new Bundle() ;
bd.putString(ContentFragment.SELECTED_ITEM,menuDrawerAdapter.getItem(position).menuTitle);
Fragment contentFragment = new ContentFragment( ) ;
contentFragment.setArguments(bd);
FragmentManager fragmentManager =getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_frame, contentFragment).commit();
//將選中的菜單項置爲高亮
menuDrawer.setItemChecked(position, true);
//將ActionBar中標題更改爲選中的標題項
setTitle(menuDrawerAdapter.getItem(position).menuTitle);
//將當前的側滑菜單關閉,調用DrawerLayout的closeDrawer()方法即可
mDrawerLayout.closeDrawer(menuDrawer);
}
public void setTitle( String title ){
currentContentTitle = title ; // 更改當前的CurrentContentTitle標題內容
getActionBar().setTitle(title);
}
}
/**側滑菜單狀態監聽器(開、關),通過繼承ActionBarDrawerToggle實現*/
private class DrawerMenuToggle extends ActionBarDrawerToggle{
/**
* @param drawerLayout :就是加載的DrawerLayout容器組件
* @param drawerImageRes : 要使用的ActionBar左上角的指示圖標
* @param openDrawerContentDescRes 、closeDrawerContentDescRes:開啓和關閉的兩個描述字段,沒有太大的用處
*
* */
public DrawerMenuToggle(Activity activity, DrawerLayout drawerLayout,
int drawerImageRes, int openDrawerContentDescRes,
int closeDrawerContentDescRes) {
super(activity, drawerLayout, drawerImageRes, openDrawerContentDescRes,closeDrawerContentDescRes);
}
/** 當側滑菜單達到完全關閉的狀態時,回調這個方法 */
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
//當側滑菜單關閉後,顯示ListView選中項的標題,如果並沒有點擊ListView中的任何項,那麼顯示原來的標題
getActionBar().setTitle(currentContentTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
/** 當側滑菜單完全打開時,這個方法被回調 */
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
getActionBar().setTitle(R.string.global_title); //當側滑菜單打開時ActionBar顯示全局標題"推酷"
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
/**爲了能夠讓ActionBarDrawerToggle監聽器
* 能夠在Activity的整個生命週期中都能夠以正確的邏輯工作
* 需要添加下面兩個方法*/
@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);
mDrawerToggle.onConfigurationChanged(newConfig);
}
/**最後做一些菜單上處理*/
@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);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//第一個if 要加上,爲的是讓ActionBarDrawerToggle以正常的邏輯工作
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
if (id == R.id.action_settings) {
return true;
}
if(id == R.id.action_websearch){
Toast.makeText(this, "webSearch 菜單項被單擊", Toast.LENGTH_SHORT).show();
}
return super.onOptionsItemSelected(item);
}
/**每次調用 invalidateOptionsMenu() ,下面的這個方法就會被回調*/
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// 如果側滑菜單的狀態監聽器在側滑菜單打開和關閉時都調用了invalidateOptionsMenu()方法,
//當側滑菜單打開時將ActionBar上的某些菜單圖標隱藏起來,使得這時僅顯示“推酷”這個全局標題
//本應用中是將ActiongBar上的action菜單項隱藏起來
boolean drawerOpen = mDrawerLayout.isDrawerOpen(menuDrawer);//判定當前側滑菜單的狀態
menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
/**《當用戶按下了"手機上的返回功能按鍵"的時候會回調這個方法》*/
@Override
public void onBackPressed() {
boolean drawerState = mDrawerLayout.isDrawerOpen(menuDrawer);
if (drawerState) {
mDrawerLayout.closeDrawers();
return;
}
//也就是說,當按下返回功能鍵的時候,不是直接對Activity進行彈棧,而是先將菜單視圖關閉
super.onBackPressed();
}
}
Fragment文件的創建——ContentFragment.java
package com.example.navigaterdrawer;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class ContentFragment extends Fragment {
public static final String SELECTED_ITEM = "selected_item" ;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Bundle bd = getArguments( ) ;
View view = inflater.inflate(R.layout.fragment_content, null) ;
( (TextView ) view ).setText(bd.getString(SELECTED_ITEM)) ;
return view ;
}
}
fragment_content.xml文件
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</TextView>
主菜單的創建—— main.xml文件
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.navigaterdrawer.MainActivity" >
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_settings"/>
<!-- 添加一個action菜單項 ,顯示一張圖片,標題設爲空-->
<item
android:id="@+id/action_websearch"
android:showAsAction="withText|ifRoom"
android:icon="@drawable/find"
android:title= ""/>
</menu>
string.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">NavigaterDrawer</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
<string name="drawer_open"> Drawer is opened </string>
<string name="drawer_close">Drawer is closed </string>
<string name="global_title">推酷</string>
</resources>
配置文件——Mainfest.xml文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.navigaterdrawer"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.DeviceDefault.Light">
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
文章參考鏈接:添加鏈接描述