菜單:Menu
作為 Android 用戶,你一定見過類似這樣的頁面:
它就是我們今天的主角——菜單,它的使用場景和作用不用多說,幾乎每個 App 都會用到它,今天我們就一起來看看 Android 提供的幾種菜單類型及用法。
1. 菜單的幾種類型
根據(jù)不同的業(yè)務場景和不同的樣式,Android 提供了以下 3 種菜單:
- Option Menu: 選項菜單
- Context Menu: 上下文菜單
- Pop-up Menu: 彈窗菜單
下面來分別介紹這 3 種菜單類型
1.1 Option Menu
選項文菜單是最常用的 Menu,可以直接通過 Android 的“菜單鍵”喚出,通常直接為當前 Activity 服務。在高版本的 Android 系統(tǒng)上是從右上角彈出,可以在里面放置一些常用的功能入口或者設置項等等高頻選項。
1.2 Context Menu
上下文菜單需要綁定在一個控件之上,當我們長按這個控件的時候就會出現(xiàn)一個懸浮窗式的菜單,通常用于設置某個控件的屬性或內容。
1.3 Popup Menu
從字面上看和上一節(jié)學的 PopupWindow 很像,沒錯,它的樣式確實和 PopupWindow 是一樣一樣的。同時它也需要綁定到一個 View 上面,然后會以一個豎直列表的形式彈出一個懸浮窗,非常適合對 View 進行設置或者提供一些相關的附加選項。
注意: Context Menu 和 Popup Menu 都需要和一個 View 綁定,但 Popup Menu 里面的選項點擊不應該直接影響到 View的內容,否則應該使用 Context Menu,Popup Menu 更多的是用于 View 相關操作的擴展。
2. Menu 資源的創(chuàng)建方法
對于以上提到的 3 種類型的菜單,你都可以通過 Java 代碼或者 XML 資源文件兩種方式創(chuàng)建,但大多數(shù)情況下我強烈推薦使用XML 的形式。用 XML 可以對菜單結構一目了然,并且和邏輯代碼物理隔離,更有利于我們維護。在編寫完 XML 菜單資源之后,在 Java 代碼中直接 inflate 加載資源文件即可。
創(chuàng)建菜單資源需要以下步驟:
- 右鍵點擊“res”目錄,依次選擇:new -> Android resource directory ,如下:
- 在彈出的窗口中輸入“menu”并選擇 Resource Type 為“menu”,點擊 OK:
- 右鍵點擊“menu”文件夾,依次選擇“New -> Menu resource file”,在 menu 目錄新增一個名為“menu.xml”的菜單資源:
創(chuàng)建完成之后,就可以開始編寫 menu.xml 文件了,一個菜單資源文件通常包含以下標簽:
-
menu:
必選標簽。用來定義一個菜單,菜單內所有的選項(item)都需要寫在<menu/>
標簽內,同時它也是整個 menu 資源文件的根節(jié)點。 -
item:
必選標簽。用來創(chuàng)建一個菜單項,每一個<item/>
標簽代表 menu 中的一個選項,另外在<item/>
中我們還可以嵌套定義<menu/>
節(jié)點,以此來創(chuàng)建一個子菜單。 -
group:
可選標簽。用來將多個<item/>
標簽做分組,它用來對菜單里的選項進行分類,這樣同類型的選項可以共享一些屬性,增強選項類別。
在了解了菜單資源標簽之后,我們就可以簡單編寫一個菜單資源了,代碼非常簡單如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/main_menu"
android:title="我要學習客戶端開發(fā)"
android:icon="@drawable/ic_launcher" >
<!-- 添加客戶端子菜單 -->
<menu>
<item android:id="@+id/submenu1"
android:title="學習 Android"
android:icon="@drawable/ic_launcher"/>
<item android:id="@+id/submenu2"
android:title="學習 iOS"
android:icon="@drawable/apple" />
</menu>
</item>
</menu>
其中<item/>
標簽支持幾種屬性來配置樣式或者行為,常用的屬性比較好理解,主要有以下 2 種:
- android:id:
菜單項的資源 ID,用來唯一標識某個選項,后續(xù)可以通過 ID 來判斷用戶點擊的是哪個菜單項。 - android:icon:
設置菜單項對應的圖標 - android:title:
設置菜單項的內容
3. 幾種菜單的使用
在第 2 小節(jié)我們已經(jīng)通過 XML 的形式完成了菜單內容的設置,接著需要在 Activity 中編寫邏輯并加載菜單資源,以下就根據(jù)不同的類型分別演示如何完成菜單的加載及使用。
3.1 Option Menu 示例
3.1.1 加載 Option Menu 資源
為了使用 Option Menu,我們需要在 Activity 中復寫onCreateOptionsMenu()
方法:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_file, menu);
return true;
}
當 Activity 創(chuàng)建 Option Menu 的時候系統(tǒng)會回調此函數(shù),我們只需要在里面 inflate 我們的菜單資源即可,其中getMenuInflater()
用來獲取一個“MenuInflater”對象,我們可以用它來加載一個 menu 資源文件——menu.xml。
3.1.2 處理菜單項的點擊事件
當用戶在菜單中點擊了某個選項之后,Android 系統(tǒng)會回調onOptionsItemSelected()
方法,并傳入被選菜單項的 Menu 實例。我們可以通過 Menu 實例的getItemId()
方法拿到菜單項對應的唯一 ID(通過<item/>
標簽的 android:id 屬性設置的),從而判斷用戶選擇的是哪一項,進而執(zhí)行相應的邏輯,代碼如下:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// 根據(jù)點擊的選項處理不同的邏輯
switch (item.getItemId()) {
case R.id.menu:
// 點擊主菜單
return true;
case R.id.submenu1:
// 點擊子菜單1
return true;
case R.id.submenu2:
// 點擊子菜單2
return true;
default:
return super.onOptionsItemSelected(item);
}
}
**注意:**在你成功處理了菜單項的點擊事件之后(我們通常稱之為消費),你需要在函數(shù)的末尾返回“true”,如果沒有消費那么可以返回false,不過建議調用
super.onOptionsItemSelected(item)
將本次點擊事件交給上層處理(上層的默認實現(xiàn)也是false)。
3.2 Context Menu 示例
3.2.1 加載 ContextMenu
加載一個 ContextMenu 通常需要以下步驟:
- 調用
registerForContextMenu()
傳入一個 View,來為該 View 注冊一個Context Menu,從此該 View 就和一個 OptionMenu 綁定; - 在 Activity 中復寫
onCreateContextMenu()
方法,當用戶長按你注冊過的 View,Android 系統(tǒng)就會回調此方法,我們可以在這里進行 menu 資源的加載。
其實邏輯和 Option Menu 類似,但是因為需要綁定 View 所以多了一個注冊操作,加載代碼如下:
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_file, menu);
}
onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
方法需要傳入 3 個參數(shù),分別是:
- ContextMenu menu: 菜單對象,類似 OptionMenu 里面的 Menu 對象
- View v: 與 Context Menu 綁定的 View 對象
- ContextMenuInfo menuInfo: 包含與被選項的一些附加信息
注意: 如果當前 Activity 有多個 View 都有 Context Menu,那么需要通過這幾個參數(shù)來判斷當前觸發(fā)的是哪個 View 相關的 Context Menu
3.2.2 處理 Context Menu 選項的點擊事件
當用戶點擊上下文菜單項的時候,系統(tǒng)會回調onContextItemSelected()
方法,所以我們可以在方法里實現(xiàn)相應的處理邏輯。如下:
@Override
public boolean onContextItemSelected(MenuItem item) {
// 處理 Context Menu 選項的點擊事件
}
}
3.3 Popup Menu 示例
3.3.1 展示 Popup Menu
和 Context Menu 類似,Popup Menu 也需要和一個 View 綁定,但二者的加載過程有些不同。加載一個 Popup Menu 需要經(jīng)過 3 個步驟:
- 調用 PopupMenu 的構造器,傳入當前 Application 的上下文對象,待綁定的 View;
- 調用
getMenuInflater()
獲取 MenuInflater對象,通過它將菜單資源裝載入 PopupMenu 的 Menu 實例中; - 調用 PopupMenu 對象的
show()
彈出菜單。
加載代碼如下:
PopupMenu popupMenu = new PopupMenu(this,view);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu,popupMenu .getMenu());
popup.show();
3.3.2 監(jiān)聽 Popup Menu 的點擊事件
為了監(jiān)聽 Popup Menu 的點擊事件,我們需要在 Activity 中實現(xiàn)PopupMenu.OnMenuItemClickListener
接口并通過setOnMenuItemclickListener()
方法注冊 Popup Menu。這樣一來,當用戶點擊菜單項的時候,Android 系統(tǒng)會回調 Activity 的onMenuItemClick()
方法,在當中處理點擊事件即可。
4. 完整示例代碼
通過以上針對每個類型 Menu 的講解,大家對菜單的創(chuàng)建和使用應該都比較清楚了,下面我們通過一個完整的示例來演示一下 3 種菜單的使用。
4.1 編寫 menu 資源
在第 2 小節(jié)中我們詳細介紹了 menu 資源,它包括<menu/>
、<item/>
、<group/>
三種標簽,為了演示方便我們直接采用第 2 小節(jié)中的菜單資源。
4.2 編寫布局
菜單本身并不涉及到布局的編寫,我們只需要兩個 View,一個綁定給 Context Menu,一個給 Popup Menu:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_context"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="30dp"
android:text="我這里有 Context Menu"
android:textSize="20sp" />
<Button
android:id="@+id/bt_popup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="pop"
android:text="我這里有 Popup Menu" />
</LinearLayout>
4.3 編寫 Activity
最后就可以編寫 Activity 了,其中要做的就是為 Menu 做資源加載,并接收點擊回調即可:
package com.emercy.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.PopupMenu;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivityimplements PopupMenu.OnMenuItemClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 為 TextView 注冊 Context Menu
registerForContextMenu(findViewById(R.id.tv_context));
}
// 加載 Option Menu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu, menu);
return true;
}
// 接收 Option Menu 的點擊
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return onItemClick(item);
}
// 加載 Context Menu
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu, menu);
}
// 接收 Context Menu 的點擊
@Override
public boolean onContextItemSelected(MenuItem item) {
return onItemClick(item);
}
// 加載 Popup Menu
public void pop(View v){
PopupMenu popup = new PopupMenu(this, v);
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu, popup.getMenu());
popup.show();
}
// 接收 Popup Menu 的點擊
@Override
public boolean onMenuItemClick(MenuItem item) {
return onItemClick(item);
}
private boolean onItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.main_menu:
Toast.makeText(this, "選擇了客戶端開發(fā)", Toast.LENGTH_SHORT).show();
break;
case R.id.submenu1:
Toast.makeText(this, "選擇學習 Android", Toast.LENGTH_SHORT).show();
break;
case R.id.submenu2:
Toast.makeText(this, "選擇學習 iOS", Toast.LENGTH_SHORT).show();
break;
}
return true;
}
}
針對每個菜單都分別有“加載資源”和“處理點擊”兩種操作,另外由于每個菜單的處理邏輯都一樣,為了增強代碼復用性我單獨拎出了一個函數(shù)onItemClick()
專門用于統(tǒng)一處理點擊事件。
最終樣式如下(在不同的設備上可能會有所不同):
- Option Menu 的子菜單:
- Context Menu 的子菜單:
- Popup Menu 的主菜單:
5. 小結
本節(jié)介紹了 Android 提供的幾種菜單:Option Menu 通常用來提供 Activity 相關的選項,Context Menu 通常用來針對某個 View 進行設置,而 Popup Menu 用來設置某個 View 的屬性或者展示一些附加功能。使用的步驟大體相同,在一個完整 App 的開發(fā)中,Menu 是必不可少的部分,希望大家能夠很好的掌握本節(jié)內容。