1. 菜單的分類(lèi)
菜單是Android應(yīng)用中非常重要且常見(jiàn)的組成部分芦倒,主要可以分為三類(lèi):選項(xiàng)菜單、上下文菜單/上下文操作模式以及彈出菜單龟再。它們的主要區(qū)別如下:
- 選項(xiàng)菜單
一個(gè)應(yīng)用的主菜單項(xiàng)呀洲,用于放置對(duì)應(yīng)用產(chǎn)生全局影響的操作,如搜索/設(shè)置啡捶。 - 上下文菜單
用戶長(zhǎng)按某一元素時(shí)出現(xiàn)的浮動(dòng)菜單姥敛。它提供的操作將影響所選內(nèi)容,主要應(yīng)用于列表中的每一項(xiàng)元素(如長(zhǎng)按列表項(xiàng)彈出刪除對(duì)話框)瞎暑。上下文操作模式將在屏幕頂部欄(菜單欄)顯示影響所選內(nèi)容的操作選項(xiàng)彤敛,并允許用戶選擇多項(xiàng),一般用于對(duì)列表類(lèi)型的數(shù)據(jù)進(jìn)行批量操作了赌。 - 彈出菜單
以垂直列表形式顯示一系列操作選項(xiàng)墨榄,一般由某一控件觸發(fā),彈出菜單將顯示在對(duì)應(yīng)控件的上方或下方勿她。它適用于提供與特定內(nèi)容相關(guān)的大量操作袄秩。
2. 選項(xiàng)菜單
XML定義Menu
使用XML和Java代碼都可以創(chuàng)建Menu。但是在實(shí)際開(kāi)發(fā)中,往往通過(guò)XML文件定義Menu之剧,但Menu的部分條目需要?jiǎng)討B(tài)顯示,便需要采用java代碼實(shí)現(xiàn),使用XML做有以下幾個(gè)好處:
- 使用XML可以獲得更清晰的菜單結(jié)構(gòu)
- 將菜單內(nèi)容與應(yīng)用的邏輯代碼分離
- 可以使用應(yīng)用資源框架贮喧,為不同的平臺(tái)版本、屏幕尺寸創(chuàng)建最合適的菜單(如對(duì)drawable猪狈、string等系統(tǒng)資源的使用)
要定義Menu箱沦,我們首先需要在res文件夾下新建menu文件夾,它將用于存儲(chǔ)與Menu相關(guān)的所有XML文件雇庙。
我們可以使用<menu>谓形、<item>、<group>三種XML元素定義Menu疆前,下面簡(jiǎn)單介紹一下它們:
- <menu>是菜單項(xiàng)的容器寒跳。<menu>元素必須是該文件的根節(jié)點(diǎn),并且能夠包含一個(gè)或多個(gè)<item>和<group>元素竹椒。
- <item>是菜單項(xiàng)童太,用于定義MenuItem,可以嵌套<menu>元素胸完,以便創(chuàng)建子菜單书释。
- <group>是<item>元素的不可見(jiàn)容器(可選)∩蘅可以使用它對(duì)菜單項(xiàng)進(jìn)行分組爆惧,使一組菜單項(xiàng)共享可用性和可見(jiàn)性等屬性。
其中锨能,<item>是我們主要需要關(guān)注的元素扯再,它的常見(jiàn)屬性如下:
android:id:菜單項(xiàng)(MenuItem)的唯一標(biāo)識(shí)
android:icon:菜單項(xiàng)的圖標(biāo)(可選)
android:title:菜單項(xiàng)的標(biāo)題(必選)
android:showAsAction:指定菜單項(xiàng)的顯示方式羞芍。常用的有ifRoom欠啤、never、always钻蔑、withText
/*
always:菜單項(xiàng)永遠(yuǎn)不會(huì)被收納到溢出菜單中倔约,因此在菜單項(xiàng)過(guò)多的情況下可能超出菜單欄的顯示范圍秃殉。
ifRoom:在空間足夠時(shí),菜單項(xiàng)會(huì)顯示在菜單欄中跺株,否則收納入溢出菜單中复濒。
withText:無(wú)論菜單項(xiàng)是否定義了icon屬性,都只會(huì)顯示它的標(biāo)題乒省,而不會(huì)顯示圖標(biāo)巧颈。使用這種方式的菜單項(xiàng)默認(rèn)會(huì)被收納入溢出菜單中。
never:菜單項(xiàng)永遠(yuǎn)只會(huì)出現(xiàn)在溢出菜單中袖扛。*/
menu_test.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/file_delete"
android:icon="@android:drawable/ic_delete"
android:showAsAction="always"
android:title="delete" />
<item
android:id="@+id/file_new"
android:showAsAction="never"
android:title="new" />
<item
android:id="@+id/file_save"
android:showAsAction="never"
android:title="save" />
<item
android:id="@+id/file_other"
android:icon="@android:drawable/ic_menu_more"
android:showAsAction="ifRoom"
android:title="more">
<menu>
<item
android:id="@+id/file_other_1"
android:title="more1" />
<item
android:id="@+id/file_other_2"
android:title="more2" />
</menu>
</item>
<item
android:id="@+id/file_more"
android:icon="@android:drawable/ic_menu_more"
android:showAsAction="never"
android:title="more">
<menu>
<item
android:id="@+id/file_more_1"
android:title="more1" />
<item
android:id="@+id/file_more_2"
android:title="more2" />
</menu>
</item>
</menu>
MainActivity.java
public class MainActivity extends Activity {
public static final String TAG = "breeze";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate: ");
}
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "onStart: ");
}
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume: ");
}
boolean shareSupport = true;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
Log.i(TAG, "onCreateOptionsMenu: ");
MenuInflater inflater = new MenuInflater(this);
inflater.inflate(R.menu.menu_test, menu);
// 動(dòng)態(tài)添加
if (shareSupport) {
menu.add(Menu.NONE, Menu.FIRST, Menu.NONE, "share");
}
// 返回true才會(huì)顯示Menu
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.file_delete:
break;
case R.id.file_new:
break;
case Menu.FIRST:
break;
}
return super.onOptionsItemSelected(item);
}
}
點(diǎn)擊3個(gè)點(diǎn)菜單后效果如圖
關(guān)于Menu java代碼常用方法還有如下
關(guān)于Menu的幾個(gè)重要的方法砸泛,都是Activity的方法十籍;
onCreateOptionsMenu(Menu menu)
每次Activity一創(chuàng)建就會(huì)執(zhí)行,一般只執(zhí)行一次唇礁;
onPrepareOptionsMenu(Menu menu)
每次menu被打開(kāi)時(shí)勾栗,該方法就會(huì)執(zhí)行一次;
onOptionsItemSelected(MenuItem item)
每次menu菜單項(xiàng)被點(diǎn)擊時(shí)盏筐,該方法就會(huì)執(zhí)行一次围俘;
invalidateOptionsMenu()
刷新menu里的選項(xiàng)里內(nèi)容,它會(huì)調(diào)用onCreateOptionsMenu(Menu menu)方法
onCreateContextMenu()
創(chuàng)建控件綁定的上下文菜單menu琢融,根據(jù)方法里的View參數(shù)識(shí)別是哪個(gè)控件綁定
onContextItemSelected(MenuItem item)
點(diǎn)擊控件綁定的上下菜單menu的內(nèi)容項(xiàng)
onCreateOptionsMenu調(diào)用時(shí)機(jī)
I/breeze ( 6261): onCreate:
I/breeze ( 6261): onStart:
I/breeze ( 6261): onResume:
I/breeze ( 6261): onCreateOptionsMenu:
Java動(dòng)態(tài)創(chuàng)建Menu
該方式就無(wú)需編寫(xiě)xml文件
@Override
public boolean onCreateOptionsMenu(Menu menu) {
Log.i(TAG, "onCreateOptionsMenu: ");
menu.add(Menu.NONE, Menu.FIRST, Menu.NONE, "share");
return true;
}
Activity+Fragment構(gòu)建的選項(xiàng)菜單
如果Activity和Fragment都加載了Menu資源界牡,那么這些菜單項(xiàng)將合并到一起。系統(tǒng)將首先顯示Activity加載的菜單項(xiàng)漾抬,隨后按每個(gè)Fragment添加到Activity中的順序顯示各Fragment的菜單項(xiàng)宿亡。如果有必要,可以使用<item>的orderInCategory屬性纳令,對(duì)菜單項(xiàng)重新排序挽荠。
在Fragment中加載Menu的方式和Activity幾乎一致,同樣需要重寫(xiě)onCreateOptionsMenu和onOptionsItemSelected方法平绩。當(dāng)然圈匆,F(xiàn)ragment中的onCreateOptionsMenu方法有所不同,如下所示:
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// XML形式menu,也可以采用動(dòng)態(tài)添加方式
inflater.inflate(R.menu.menu_test,menu);
}
其調(diào)用時(shí)機(jī)在onResume方法后,
需要注意,要讓Fragment中的菜單項(xiàng)顯示出來(lái)馒过,還需要在Fragment中調(diào)用setHasOptionsMenu(true)方法
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 調(diào)用該方法后才會(huì)顯示Menu
setHasOptionsMenu(true);
}
當(dāng)菜單項(xiàng)發(fā)生點(diǎn)擊事件時(shí)臭脓,如果Activity包括Fragment,則系統(tǒng)將依次為Activity和每個(gè)Fragment(按照每個(gè)Fragment的添加順序)調(diào)用onOptionsItemSelected方法腹忽,直到有一個(gè)返回結(jié)果為true或所有Fragment都調(diào)用完畢為止。因此砚作,無(wú)論是Activity還是Fragment窘奏,onOptionsItemSelected方法中的switch語(yǔ)句塊中的default分支都不要直接返回true,而應(yīng)該使用return super.onOptionsItemSelected(item)葫录,避免截?cái)嗔瞬藛雾?xiàng)的點(diǎn)擊事件.
待有時(shí)間繼續(xù)補(bǔ)充該文章