1. 程式人生 > >安卓menu的介紹與使用

安卓menu的介紹與使用

選單之前是使用者點選系統的選單鍵才展示出來的,後來這個鍵漸漸被移除,選單變成了點選任意的view都可以展示。選單非為3種:

  1.Options menu and action bar  選項選單和操作欄

  2.Context menu and contextual action mode 上下文選單和上下文動作模式

  3.Popup menu  彈出式選單

現在逐一介紹這3種菜單的使用方法:

1.Options menu

  這個選單比較原始,它的實現必須通過點選actionbar 上的按鈕或手機自帶的選單鍵才能顯示。首先,在res檔案目錄下,新建資料夾menu,然後再menu資料夾中新建menu的xml檔案,這裡我的檔名為"option_menu".

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/add"
        android:icon="@mipmap/addition"
        android:title="新增"/>
    <item android:id="@+id/see"
        android:icon="@mipmap/eye"
        android:title
="發現"/> <item android:id="@+id/state" android:icon="@mipmap/emoji" android:title="表情"/> </menu>

 我自己在mipmap資料夾中放了3張40*40 的小圖示(你可以從圖示網站自己去下載),這個xml檔案比較簡單。接著我們在activity中把這個xml填充成view。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void
onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.option_menu,menu); return true; } }

這是點選actionbar右邊的按鈕彈出的介面截圖,但奇怪的是我在xml配置的圖示沒顯示出來 ̄︿ ̄。通過百度,原來是menu這個物件搞的鬼

我在這裡打斷點時可以發現menu在執行時實際上引用的是MenuBuilder物件。這個MenuBuilder物件和menu是什麼關係呢? 通過sdk查詢,他倆的關係是:

MenuBuilder------實現-----》SupportMenu(介面)-------繼承--------》Menu(介面)。而在MenuBuilder這個類中控制圖示顯示的方法是:

初始時,mOptionlIconsVisible = false,我們只要呼叫setOptionalIconsVisible(true),就能解決問題。操作執行時的menuBuilder物件,很容易讓我們想到用反射。。。我們寫個方法,通過MenuBuilder的class物件,來調我們setOptionalIconsVisible方法。

懂反射的語法,上面的方法應該很容易就能看懂了。最後看看效果:

大功告成!接下來就來監聽選單的點選事件了,方法是onOptionsItemSelected(),見名思意,這個方法和onCreateOptionsMenu()方法的關鍵字都是option,通過androidstudio強大的提示功能,也不用去記全名。

這裡我只寫了選單中其中一項的點選事件,其他的類似。提醒一點:這裡的switch語句不像通常那樣用break,而是用return true,有兩個原因:1.我們用break,最後還是要在switch語句結束後,返回布林值給方法,還不如在case 中直接返回。2:這一點更重要,方法要求返回布林結果就是為了消費這次點選事件,true就是消費,false不消費,如果不消費,那麼這個點選事件會繼續傳遞給activity裡的fragment。而我們這個簡單到什麼都沒有,所有返回true還是false,沒什麼影響,但建議return true來消費這次點選事件。

好了,最簡單的選項選單已經介紹完了,接下來看看更高階一點的上下文選單。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2.Context menu

對於第一個optionmenu 只跟actionBar關係好的這個事實,讓開發人員不滿意:我一個介面這麼多元素難道就不能彈選單嗎?那麼上下文選單的出現就可以讓我們少些抱怨。上下文選單分為兩種:

(1) floating context menu  浮動上下文選單:它的效果是當你長按控制元件時,會在螢幕中央出現一個列表。類似於你長按qq訊息列表中的某一項,會彈出置頂、刪除等選項

先完成一個小目標,點選一個按鈕,彈出浮動上下文選單。

老規矩:定義個float_menu.xml。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/top"
        android:icon="@mipmap/up"
        android:title="置頂" />
    <item
        android:id="@+id/delete"
        android:icon="@mipmap/delete"
        android:title="刪除" />
</menu>

佈局中加一個按鈕:

這是activity中的程式碼:

長按按鈕,出現的結果如圖:

我的圖示怎麼又不見了!!!難道之前的那個setIconEnable()方法失靈了。真是到處是坑。我通過打斷點檢視menu這個物件,結果如圖:

看看之前這裡得到的是MenuBuilder物件,現在建立ContextMenu,就成了ContextMenuBuilder物件。我查了這個類,結果發現ContextMenuBuilder繼承MenuBuilder,那就好辦了,將setIconEnable()方法改一行就OK:

圈起來的就是獲取父類的class物件,來看看結果:

可愛的圖示終於又出現了。針對一個view彈出浮動選單,除了不要忘記對控制元件註冊上下文選單,整體而言,還算簡單。現在看看對listview 註冊上下文選單。別擔心,更上面的程式碼有90%是一樣的,不管怎麼,把它做出來,也很有成就感。

1.先把佈局中的按鈕換成listview:

2.這是activity更改的程式碼,另外的兩個方法onCreateContextMenu()和 setIconEnable() 都未做更改:

3.當你長按列表中任意一項出現的結果如圖:

4.處理點選浮動選單事件:

注意:如果是普通的view,紅線那行是不需要的,其中info,position是長按項在list中的角標。

(2) contextual action mode 上下文操作模式,它會在螢幕頂部彈出 context action bar(簡稱CAB) .它的用處在於,你看到一段不錯的文字,先把他複製下來,你長按控制元件就會在頂部出現CAB,操作完後再關掉CAB,很方便。

我們基於上面的listview再做修改來展示出CAB。

1.修改onCreate()裡的程式碼:

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listView = findViewById(R.id.listview);
        Random random = new Random();
        for (int i=0;i<array.length;i++){
            array[i] =String.valueOf(random.nextInt(1000));
        }
        //就因為這行程式碼,使按鈕的長按事件與onCreateContextMenu建立了聯絡,所以非常重要
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,array);
        listView.setAdapter(adapter);

        listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
        listView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                Log.d(TAG,"onCreateActionMode");
                MenuInflater inflater = mode.getMenuInflater();
                inflater.inflate(R.menu.float_menu,menu);
                return true;
            }

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                Log.d(TAG,"onPrepareActionMode");
                return false;
            }

            @Override
            public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
                //長按控制元件呼叫的第一個方法。
                Log.d(TAG,"onItemCheckedStateChanged");
            }

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                Log.d(TAG,"onActionItemClicked");
                switch (item.getItemId()){
                    case R.id.top:
                        Toast.makeText(MainActivity.this, "置頂", Toast.LENGTH_SHORT).show();
                        mode.finish();
                        return true;
                    default:
                        return false;
                }
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {
                Log.d(TAG,"onDestroyActionMode");
            }
        });
    }

上面建立setMultiChoiceModeListener()的方法回撥順序,我特地進行了調整成了它回撥的順序,有前到後。5個回撥中,當你長按listview中的某一項是,最先回調的是前3個方法,點選點選了頭部CAB後,才會呼叫後兩個。其中mode.finisha()如果不加進去,那麼頭部欄是不會消失的。最終結果圖為:

這裡只有圖示,文字不見,我沒有追究了,哎!這種從最上面彈出的actionbar更高階些。它把我們從點選控制元件到彈出bar,再到點選選單項的全部過程用5個回撥,解析的很全面。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

3.Popup menu  彈出式選單:

熟悉popopwindow 的情形下,使用popupmenu應該會覺得很容易。在預設情形下:popup menu 顯示在控制元件上面,如果空間不過,則在下方顯示,當前也可以自己自定義位置顯示。它的使用與第一種options menu99%相似。

將layout中的listview再改回button,這就不上截圖了,直接看acvity中的程式碼就一目瞭然。

public class MainActivity extends AppCompatActivity implements PopupMenu.OnMenuItemClickListener{
    private static final String TAG = "MainActivity";
    private Button showPopMenuBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        showPopMenuBtn = findViewById(R.id.showPopmenuBtn);
        showPopMenuBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                PopupMenu popup = new PopupMenu(MainActivity.this,v);
                MenuInflater inflater = popup.getMenuInflater();
                inflater.inflate(R.menu.option_menu,popup.getMenu());
                setIconEnable(popup.getMenu(),true);
                popup.show();//這裡給popup設定監聽事件,而整個activity實現了監聽。
                popup.setOnMenuItemClickListener(MainActivity.this);
            }
        });
    }

    public void setIconEnable(Menu menu, boolean isVisible){
        if (menu !=null){
            try {
                Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible",boolean.class);
                method.setAccessible(true);
                method.invoke(menu,isVisible);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        switch (item.getItemId()){
            case R.id.add:
                Toast.makeText(MainActivity.this,"新增",Toast.LENGTH_SHORT).show();
                return true;
            default:
                return false;

        }
    }

執行結果如圖:

從popup menu設計初衷上,也只是為了對單個控制元件選定進行了操作,跟上下文選單中的浮動上下文選單功能是一模一樣的,甚至官方推薦你用第二種。只不過由於popwindow自身的屬性,所以讓他在menu中也佔了一席之地。我自人以為,如果你想點個控制元件,讓它彈出選單,用第二種是最好的。其中第二種上下文選單中的浮動選單比較簡單,但可以滿足非常多的普通需求,當你需要更詳細的互動過程控制,就考慮上下文選單中第二種操作模式。由於popmenu可以自定義位置顯示選單,它也算小巧而靈活。

最後一點:不要被這篇部落格的滾動條給嚇到,裡面有很多程式碼、結果截圖,真正有用的程式碼少的可憐。( ̄︶ ̄)