TShopping

 找回密碼
 註冊
搜索
查看: 1826|回復: 0

[教學] Android系列之UI組件----Menu、PopupMenu菜單

[複製鏈接]
發表於 2016-12-28 08:19:45 | 顯示全部樓層 |閱讀模式
 
Push to Facebook
從官方文檔了解到,從Android3.0(API level 11)開始,Android設備不再要求提供一個專門的菜單按鈕,轉而推薦使用ActionBar。所以現在市面上很多新設備使用三個虛擬按鍵,並不再額外提供菜單按鈕。

因為Android版本的發展,對於菜單的支持各個版本有很大的區別,而Android3.0是個分水嶺,大概可以分為下面三類:

OptionMenu和ActionBar:一些操作的集合,如果開發的平台在Android3.0之上,推薦使用ActionBar,如果開發的平台在Android2.3或之下,還是可以使用OptionMenu的。
ContextMenu和ActionMode:ContextMenu是一個浮動的窗口形式展現一個選項列表,ActionMode是一個顯示在屏幕頂部的操作欄,允許用戶選擇多個選項,ActionMode在Android3.0之後才有支持。
Popup Menu:PopupMenu是固定在View上的模態菜單,以彈出的方式顯示,在Android3.0之後才有支持。
【在XML中定義一個菜單】

Android提供了標準的XML格式的資源文件來定義菜單項,並且對所有菜單類型都支持,推薦使用XML資源文件來定義菜單,之後再把它Inflater到Activity或者Fragment中,而不是在Activity中使用代碼聲明。

而菜單的XML資源文件,需要創建在/res/menu/目錄下,並且包含一下幾個元素:

<menu>:定義一個Menu,是一個菜單資源文件的根節點,裡面可以包含一個或者多個<item>和<group>元素。
<item>:創建一個MenuItem,代表了菜單中一個選項。
<group>:對菜單項進行分組,可以以組的形式操作菜單項。
<item>元素除了常規的id、icon、title屬性的支持,還有一個重要的屬性:android:showAsAction,這個屬性是起兼容性的,描述了在Android的高版本中,菜單項何時以何種方式加入到ActionBar中。

<group>是對菜單進行分組,分組後的菜單顯示效果並沒有區別,唯一的區別在於可以針對菜單組進行操作,這樣對於分類的菜單項,操作起來更方便,提供如下的操作:

Menu.setGroupCheckable():菜單組內的菜單是否都可選。
Menu.setGroupVisible():是否隱藏菜單組的所有菜單。
Menu.setGroupEnabled():菜單組的菜單是否有用。
如果菜單項需要單選或者多選,可以使用android:checkableBehavior屬性設置,它可以對單個<item>或者<group>設置一個組,這個屬性接受三個參數:single,單選;all,多選, none,沒有Checked的選項,默認。

當創建好一個XML菜單資源文件之後,可以使用MenuInflater.inflate()方法填充菜單資源,使XML資源變成一個可編程的對象。



一、Options menu選項菜單:

OptionMenu,選項菜單,單擊手機上的菜單鍵(MENU)出現,必須設備具有菜單按鈕才可以觸發。因為屏幕的限制,最多只能展示六個菜單項,如果定義的菜單項超出了六個,其他的菜單項將被隱藏,第六個菜單將會顯示“更多”,點擊展開更多的菜單。雖說在Android3.0之後不再推薦使用選項菜單,但是如果使用了,在Android3.0之後的設備上,選項菜單項將被默認轉移到ActionBar中,這個可以通過android:showAsAction屬性控制。

創建選項菜單的核心步驟:

(1)重寫Activity的onCreateOptionMenu(Menu menu)方法,當菜單第一次被加載時調用

(2)調用Menu 的add( )方法添加菜單項(MenuItem),同時可以調用MenuItem的setIcon()方法為菜單項設置圖標(注:Android 3.0之後,即使添加了圖標也不會顯示)

(3)重寫Activity的OptionsItemSelected(MenuItem item)來響應菜單項(MenuItem)的點擊事件

來看一下具體的代碼實現:

新建的Android工程MenuTest:

【方式一】通過配置文件添加Menu選項

(1)在res/menu/main.xml中定義菜單項。main.xml的代碼如下:

  1. <menu xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     tools:context="com.example.menutest.MainActivity" >

  4.     <item
  5.         android:id="@+id/start"
  6.         android:orderInCategory="100"
  7.         android:showAsAction="never"
  8.         android:title="@string/start"/>
  9.    
  10.         <item
  11.         android:id="@+id/over"
  12.         android:orderInCategory="200"
  13.         android:showAsAction="never"
  14.         android:title="@string/over"/>

  15. </menu>
複製代碼

注:第9行和第15行的字符串引用,需要提前在strings.xml文件中設置好。

(2)MainActivity.java:

  1. package com.example.menutest;

  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.Menu;
  5. import android.view.MenuItem;
  6. import android.widget.Toast;


  7. public class MainActivity extends Activity {

  8.     @Override
  9.     protected void onCreate(Bundle savedInstanceState) {
  10.         super.onCreate(savedInstanceState);
  11.         setContentView(R.layout.activity_main);
  12.     }


  13.     //重写onCreateOptionMenu(Menu menu)方法,当菜单第一次被加载时调用
  14.     @Override
  15.     public boolean onCreateOptionsMenu(Menu menu) {
  16.         // Inflate the menu; this adds items to the action bar if it is present.
  17.         //填充选项菜单(读取XML文件、解析、加载到Menu组件上)
  18.         getMenuInflater().inflate(R.menu.main, menu);
  19.         return true;
  20.     }

  21.     //重写OptionsItemSelected(MenuItem item)来响应菜单项(MenuItem)的点击事件(根据id来区分是哪个item)
  22.     @Override
  23.     public boolean onOptionsItemSelected(MenuItem item) {
  24.         // Handle action bar item clicks here. The action bar will
  25.         // automatically handle clicks on the Home/Up button, so long
  26.         // as you specify a parent activity in AndroidManifest.xml.
  27.         switch (item.getItemId()) {
  28.         case R.id.start:
  29.             Toast.makeText(this, "开始游戏", Toast.LENGTH_SHORT).show();
  30.             break;
  31.         case R.id.over:
  32.             Toast.makeText(this, "结束游戏", Toast.LENGTH_SHORT).show();
  33.             break;

  34.         default:
  35.             break;
  36.         }
  37.         return super.onOptionsItemSelected(item);
  38.     }
  39. }
複製代碼

核心代碼是第24行:引用佈局文件menu.xml,然後在30行的方法中添加MenuItem的點擊事件。

運行程序,效果如下:
1.gif


如果想讓MenuItem變成ActionBar的形式,可以修改res/menu/main.xml中的android:showAsAction屬性,它的屬性值一共有下面幾種:
2.png


其中,ifRoom表示:如果有空間,就顯示出來。withText表示:只顯示文本(如果配了圖標的話)。如果將屬性設置為always,效果如下:
3.gif


如果需要添加子菜單,可以修改menu.xml文件為如下所示:

  1. <menu xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     tools:context="com.example.menutest.MainActivity" >

  4.     <item
  5.         android:id="@+id/start"
  6.         android:orderInCategory="100"
  7.         android:showAsAction="never"
  8.         android:title="@string/start"/>
  9.     <item
  10.         android:id="@+id/over"
  11.         android:orderInCategory="200"
  12.         android:showAsAction="never"
  13.         android:title="@string/over"/>
  14.    
  15.     <!-- 子菜单 -->
  16.     <item
  17.         android:id="@+id/setting"
  18.         android:title="setting">
  19.         <menu>
  20.             <item
  21.                 android:id="@+id/setting1"
  22.                 android:orderInCategory="300"
  23.                 android:showAsAction="never"
  24.                 android:title="声音設置"/>
  25.             <item
  26.                 android:id="@+id/setting2"
  27.                 android:orderInCategory="400"
  28.                 android:showAsAction="never"
  29.                 android:title="背景設置"/>
  30.         </menu>
  31.     </item>

  32. </menu>
複製代碼

於是,子菜單的點擊事件為:

  1. public boolean onOptionsItemSelected(MenuItem item) {
  2.         // Handle action bar item clicks here. The action bar will
  3.         // automatically handle clicks on the Home/Up button, so long
  4.         // as you specify a parent activity in AndroidManifest.xml.
  5.         switch (item.getItemId()) {
  6.         case R.id.start:
  7.             Toast.makeText(this, "开始游戏", Toast.LENGTH_SHORT).show();
  8.             break;
  9.         case R.id.over:
  10.             Toast.makeText(this, "结束游戏", Toast.LENGTH_SHORT).show();
  11.             break;
  12.             
  13.         case R.id.setting1:
  14.             Toast.makeText(this, "声音設置", Toast.LENGTH_SHORT).show();
  15.             break;
  16.             
  17.         case R.id.setting2:
  18.             Toast.makeText(this, "背景設置", Toast.LENGTH_SHORT).show();
  19.             break;
  20.         default:
  21.             break;
  22.         }
  23.         return super.onOptionsItemSelected(item);
  24.     }
複製代碼

運行效果如下:
4.gif




【方式二】通過Java代碼添加Menu選項:

當然了,上方的方式一是通過xml文件來添加Menu選項的,下面我們通過Java代碼來添加Menu選項(此時已經不需要menu.xml文件了)。修改MainActivity.java,代碼如下:

MainActivity.java:

  1. package com.example.menutest;

  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.Menu;
  5. import android.view.MenuItem;
  6. import android.view.SubMenu;
  7. import android.widget.Toast;


  8. public class MainActivity extends Activity {

  9.    
  10.     private static final int START_ITEM = Menu.FIRST;  //Menu.FIRST的值就是1
  11.     private static final int OVER_ITEM = Menu.FIRST+1;
  12.     private static final int SET_ITEM1 = Menu.FIRST+2;
  13.     private static final int SET_ITEM2 = Menu.FIRST+3;
  14.    
  15.    
  16.     @Override
  17.     protected void onCreate(Bundle savedInstanceState) {
  18.         super.onCreate(savedInstanceState);
  19.         setContentView(R.layout.activity_main);
  20.     }


  21.     //重写onCreateOptionMenu(Menu menu)方法,当菜单第一次被加载时调用
  22.     @Override
  23.     public boolean onCreateOptionsMenu(Menu menu) {
  24.         // Inflate the menu; this adds items to the action bar if it is present.
  25.         //填充选项菜单(读取XML文件、解析、加载到Menu组件上)
  26.        // getMenuInflater().inflate(R.menu.main, menu);
  27.         
  28.         //通过代码的方式来添加Menu
  29.         //添加菜单项(组ID,菜单项ID,排序,标题)
  30.         menu.add(0, START_ITEM, 100, "Start");
  31.         menu.add(0, OVER_ITEM, 200, "Over");
  32.         //添加子菜单
  33.         SubMenu sub1 = menu.addSubMenu("setting");
  34.         sub1.add(1, SET_ITEM1, 300, "声音设置");
  35.         sub1.add(1, SET_ITEM2, 400, "背景设置");
  36.         
  37.         return true;
  38.     }

  39.     //重写OptionsItemSelected(MenuItem item)来响应菜单项(MenuItem)的点击事件(根据id来区分是哪个item)
  40.     @Override
  41.     public boolean onOptionsItemSelected(MenuItem item) {
  42.         // Handle action bar item clicks here. The action bar will
  43.         // automatically handle clicks on the Home/Up button, so long
  44.         // as you specify a parent activity in AndroidManifest.xml.
  45.         switch (item.getItemId()) {
  46.         case START_ITEM:
  47.             Toast.makeText(this, "开始游戏", Toast.LENGTH_SHORT).show();
  48.             break;
  49.         case OVER_ITEM:
  50.             Toast.makeText(this, "结束游戏", Toast.LENGTH_SHORT).show();
  51.             break;
  52.             
  53.         case SET_ITEM1:
  54.             Toast.makeText(this, "声音設置", Toast.LENGTH_SHORT).show();
  55.             break;
  56.             
  57.         case SET_ITEM2:
  58.             Toast.makeText(this, "背景設置", Toast.LENGTH_SHORT).show();
  59.             break;

  60.         default:
  61.             break;
  62.         }
  63.         return super.onOptionsItemSelected(item);
  64.     }
  65. }
複製代碼

注意第35行對各個參數的解釋。

運行程序,效果和上方gif圖的效果是一樣的。

總結:推薦用方式1來做。



二、Context menu:上下文菜單

顧名思義與上下文(環境)有關。操作時需要長時間按住某個item不放,就會彈出Context menu。效果如下:
5.png


創建上下文菜單的核心步驟:

(1)覆蓋Activity的onCreateContextMenu(Menu menu)方法,調用Menu的add()方法添加菜單項(MenuItem)

(2)覆蓋Activity的onContextItemSelected(MenuItem iitem)來響應事件

(3)調用registerForContextMenu()方法來為視圖註冊上下文菜單。

現在通過代碼來實現。

重新建一個Android工程MenuTest02,步驟如下:

我們現在activity_main.xml中添加一個按鈕button1,代碼就不寫了。然後繼續:

(1)在res/menu/main.xml中定義菜單項。main.xml的代碼如下:

  1. <menu xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     tools:context="com.example.menutest02.MainActivity" >

  4.     <item
  5.         android:id="@+id/start"
  6.         android:orderInCategory="100"
  7.         android:showAsAction="never"
  8.         android:title="@string/start"/>
  9.     <item
  10.         android:id="@+id/over"
  11.         android:orderInCategory="200"
  12.         android:showAsAction="never"
  13.         android:title="@string/over"/>

  14. </menu>
複製代碼

(2)MainActivity.java:

  1. package com.example.menutest02;

  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.ContextMenu;
  5. import android.view.MenuItem;
  6. import android.view.View;
  7. import android.view.ContextMenu.ContextMenuInfo;
  8. import android.widget.Button;
  9. import android.widget.Toast;


  10. public class MainActivity extends Activity   {

  11.     private Button button1;
  12.     @Override
  13.     protected void onCreate(Bundle savedInstanceState) {
  14.         super.onCreate(savedInstanceState);
  15.         setContentView(R.layout.activity_main);
  16.         button1 = (Button)findViewById(R.id.button1);
  17.         //为按钮绑定上下文菜单(注意不是绑定监听器)
  18.         registerForContextMenu(button1);
  19.     }
  20.    
  21.     //创建上下文菜单
  22.     @Override
  23.     public void onCreateContextMenu(ContextMenu menu, View v,
  24.             ContextMenuInfo menuInfo) {
  25.         super.onCreateContextMenu(menu, v, menuInfo);
  26.         
  27.         getMenuInflater().inflate(R.menu.main, menu);
  28.     }
  29.    
  30.     //上下文菜单的触发事件
  31.     @Override
  32.     public boolean onContextItemSelected(MenuItem item) {
  33.         switch (item.getItemId()) {
  34.         case R.id.start:
  35.             Toast.makeText(this, "开始···", Toast.LENGTH_SHORT).show();
  36.             break;
  37.             
  38.         case R.id.over:
  39.             Toast.makeText(this, "结束···", Toast.LENGTH_SHORT).show();
  40.             break;

  41.         default:
  42.             break;
  43.         }        
  44.         
  45.         return super.onContextItemSelected(item);
  46.     }

  47. }
複製代碼

核心代碼是第22行:為按鈕button1綁定上下文菜單。注意不是綁定監聽器哦,不要一看到按鈕就綁定監聽器哈。

注:一個界面中只能有一個上下文菜單。

運行程序,長按button,效果如下:
6.gif


注:如果是在java代碼中添加Menu,用參數menu來添加就行了。



三、Popup menu:彈出式菜單

 PopupMenu,彈出菜單,一個模態形式展示的彈出風格的菜單,綁在在某個View上,一般出現在被綁定的View的下方(如果下方有空間)。

注意:彈出菜單是在API 11和更高版本上才有效的。

核心步驟:

(1)通過PopupMenu的構造函數實例化一個PopupMenu對象,需要傳遞一個當前上下文對像以及綁定的View。

(2)調用PopupMenu.setOnMenuItemClickListener()設置一個PopupMenu選項的選中事件。

(3)使用MenuInflater.inflate()方法加載一個XML文件到PopupMenu.getMenu()中。

(4)在需要的時候調用PopupMenu.show()方法顯示。

現在通過代碼來實現。重新新建一個工程文件MenuTest03。步驟如下:

先在佈局文件activity_main.xml中加一個按鈕,代碼略。

(1)在res/menu/main.xml中定義菜單項。
main.xml的代碼如下:

  1. <menu xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     tools:context="com.example.menutest03.MainActivity" >

  4.     <item
  5.         android:id="@+id/copy"
  6.         android:orderInCategory="100"
  7.         android:title="复制"/>
  8.    
  9.     <item
  10.         android:id="@+id/delete"
  11.         android:orderInCategory="100"
  12.         android:title="粘贴"/>

  13. </menu>
複製代碼

(2)MainActivity.java:

  1. package com.example.menutest03;

  2. import android.app.Activity;import android.os.Bundle;
  3. import android.view.MenuInflater;
  4. import android.view.MenuItem;
  5. import android.view.View;
  6. import android.view.View.OnClickListener;
  7. import android.widget.Button;
  8. import android.widget.PopupMenu;
  9. import android.widget.PopupMenu.OnMenuItemClickListener;
  10. import android.widget.Toast;


  11. public class MainActivity extends Activity implements OnClickListener,OnMenuItemClickListener{

  12.    
  13.     private Button button1;
  14.     @Override
  15.     protected void onCreate(Bundle savedInstanceState) {
  16.         super.onCreate(savedInstanceState);
  17.         setContentView(R.layout.activity_main);
  18.         button1 = (Button)findViewById(R.id.button1);
  19.         button1.setOnClickListener(this);
  20.     }

  21.     //点击按钮后,加载弹出式菜单
  22.     @Override
  23.     public void onClick(View v) {
  24.         //创建弹出式菜单对象(最低版本11)
  25.         PopupMenu popup = new PopupMenu(this, v);//第二个参数是绑定的那个view
  26.         //获取菜单填充器
  27.         MenuInflater inflater = popup.getMenuInflater();
  28.         //填充菜单
  29.         inflater.inflate(R.menu.main, popup.getMenu());
  30.         //绑定菜单项的点击事件
  31.         popup.setOnMenuItemClickListener(this);
  32.         popup.show(); //这一行代码不要忘记了
  33.         
  34.     }

  35.     //弹出式菜单的单击事件处理
  36.     @Override
  37.     public boolean onMenuItemClick(MenuItem item) {
  38.         // TODO Auto-generated method stub
  39.         switch (item.getItemId()) {
  40.         case R.id.copy:
  41.             Toast.makeText(this, "复制···", Toast.LENGTH_SHORT).show();
  42.             break;

  43.         case R.id.delete:
  44.             Toast.makeText(this, "删除···", Toast.LENGTH_SHORT).show();
  45.             break;
  46.         default:
  47.             break;
  48.         }
  49.         return false;
  50.     }
  51.    
  52. }
複製代碼

注意14行代碼綁定了兩個監聽器:OnClickListener和OnMenuItemClickListener。在綁定OnMenuItemClickListener監聽器時,選的是下面這個:

8.png



如果是在API 14及以上版本,32行34行可以合併為:popup.inflate(R.menu.main, popup.getMenu());

注意第37行代碼不要忘記show。

運行程序,單擊button,效果如下:
7.gif


文章來源





 

臉書網友討論
*滑块验证:
您需要登錄後才可以回帖 登錄 | 註冊 |

本版積分規則



Archiver|手機版|小黑屋|免責聲明|TShopping

GMT+8, 2024-3-19 14:58 , Processed in 0.088838 second(s), 26 queries .

本論壇言論純屬發表者個人意見,與 TShopping綜合論壇 立場無關 如有意見侵犯了您的權益 請寫信聯絡我們。

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回復 返回頂部 返回列表