Android 系统默认的菜单和ActionBar的使用

一、普通的Menu的创建


Menu【API】

 

1、Menu接口定义了如下方法来添加菜单:

  • MenuItem add(int titleRes):添加一个新的菜单项。
  • MenuItem add(int groupId,int itemId,int order,CharSequence title):添加一个新的处于groupId组的菜单项。
  • MenuItem add(int groupId,int itemId,int order,int titleRes):添加一个新的处于groupId组的菜单项。
  • MenuItem add(CharSequence title):添加一个新的菜单项。

参数 groupId——为当前的菜单指定一个组别,

这是由于在早期版本的Android 中提出,可以在菜单中进行嵌套,即添加子菜单,那么这时候,我们就要为不同的子菜单中各个菜单项指定一个相同的组别,不同的字菜单中菜单项应该指定不同的组别,但是现在一般不再菜单中在划分子菜单了,即只是用一级菜单,所以这个字段的使用已经不再重要

参数itemId——为当前的菜单项指定一个ID,通过这个ID能够唯一的确定当前单单击的是哪一个菜单项

参数order——指定当前的菜单项在整个菜单中的顺序,如果对于顺序不关心的话,可以使用Menu.NONE来填充这个参数

参数title——如果是使用CharSequence,那么我们可以直接在add()方法中加入String字符串,即add(0,1,Menu.NONE ,"项目一"),如果使用的是int , 那么这个参数应该是使用R.string.name的形式,即使用string.xml文件中的字符串

2、setIcon(int iconRes) 为当前的菜单项指定图标

 

【问题】

 在Android4.0系统中,创建菜单Menu,通过setIcon方法给菜单添加图标是无效的,图标没有显出来,2.3系统中是可以显示出来的。这个问题的根本原因在于4.0系统中,涉及到菜单的源码类 MenuBuilder做了改变,该类的部分源码如下:

 1 public class MenuBuilder implements Menu {
 2 ...
 3 private boolean mOptionalIconsVisible = false;
 4 ....
 5     void setOptionalIconsVisible(boolean visible) {
 6         mOptionalIconsVisible = visible;
 7     }
 8 
 9     boolean getOptionalIconsVisible() {
10         return mOptionalIconsVisible;
11     }
12 ...
13 }

上面的代码中,mOptionalIconsVisible成员初始值默认为false,这就是为什么给菜单设置图标没有效果的原因;所以,只要我们在创建菜单时通过调用setOptionalIconsVisible方法设置mOptionalIconsVisible为true就可以了;

这时候问题来了,要想调用该方法,就需要创建MenuBuilder对象,但是,我们是无法在开发的应用程序中创建MenuBuilder这个对象的(MenuBuilder为系统内部的框架类);这时候就需要考虑用反射了,在代码运行创建菜单的时候通过反射调用setOptionalIconsVisible方法设置mOptionalIconsVisible为true,然后在给菜单添加Icon,这样就可以在菜单中显示添加的图标了;

 

【成功实例】 

 1 public class MainActivity extends Activity {
 2     
 3     //用作标记菜单的ID
 4     final int Item_1 = 0x001 ;
 5     final int Item_2 = 0x002 ;
 6     final int Item_3 = 0x003 ;
 7 
 8     @Override
 9     protected void onCreate(Bundle savedInstanceState) {
10         super.onCreate(savedInstanceState);
11         setContentView(R.layout.activity_main);
12         
13     }
14 
15     @Override
16     public boolean onCreateOptionsMenu(Menu menu)
17     {
18         //调用自定义的方法,设定可以显示图标
19         setIconEnable(menu, true);  
20                  
21         MenuItem item1 = menu.add(0, Item_1, Menu.NONE, "发起群聊");  
22         item1.setIcon(R.drawable.item_1); 
23                  
24         MenuItem item2 = menu.add(0, Item_2, Menu.NONE, "创建社区");  
25         item2.setIcon(R.drawable.item_2);  
26               
27         MenuItem item3 = menu.add(0, Item_3, Menu.NONE, "传送文件");  
28         item3.setIcon(R.drawable.item_3);  
29 
30         return super.onCreateOptionsMenu(menu);
31     }
32 
33     @Override
34     // 选项菜单的菜单项被单击后的回调方法
35     public boolean onOptionsItemSelected(MenuItem mi)
36     {
37         //在这个方法中应该实现菜单项单击事件的相应,通过判定mi.getItemId()的返回值,来断定
38         //当前被单击的菜单项,之后进行具体的业务的处理
39         return true; 
40     }
41     //自定义方法,用反射机制实现图标的显示
42     private void setIconEnable(Menu menu, boolean enable)  
43         {  
44             try   
45             {  
46                 Class<?> clazz = Class.forName("com.android.internal.view.menu.MenuBuilder");  
47                 Method m = clazz.getDeclaredMethod("setOptionalIconsVisible", boolean.class);  
48                 m.setAccessible(true);  
49                   
50                 //MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征)  
51                 m.invoke(menu, enable);  
52                   
53             } catch (Exception e)   
54             {  
55                 e.printStackTrace();  
56             }  
57         }  
58 }

最终效果:

 

 

【使用XML创建菜单】

1、一般推荐使用XML资源文件来定义菜单,这种方式可以提高更好的解耦。

菜单资源文件通常应该放在/res/menu文件夹下,菜单资源的根元素通常是<menu.../>元素,<menu.../>元素无须指定任何属性(即使指定了,也是无效的)。

<menu.../>元素内可包含<item.../>元素:定义菜单项。

2、<item.../>元素可以指定如下常用属性。

android:id:为菜单项指定一个唯一标识。

android:title:指定菜单项的标题。

android:icon:指定菜单项的图标。

3、 一旦在程序中定义了菜单资源后,接下来还是重写onCreateOptionsMenu(用于创建选项菜单),调用MenuInflater对象的inflate方法装载指定资源对应的菜单即可

4、我们将上面的菜单用XML资源实现:

res/menu/my_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.penglee.menu_test.MainActivity" >
 4 
 5     <item
 6         android:id="@+id/item_1"
 7         android:title="发起群聊"
 8         android:icon="@drawable/item_1"/>
 9     
10     <item
11         android:id="@+id/item_2"
12         android:title="创建社区"
13         android:icon="@drawable/item_2"/>
14     
15     <item
16         android:id="@+id/item_3"
17         android:title="传送文件"
18         android:icon="@drawable/item_3"/>
19 
20 </menu>

主Activity文件:

 1 public class MainActivity extends Activity {
 2     
 3     TextView textView ;
 4     
 5     @Override
 6     protected void onCreate(Bundle savedInstanceState) {
 7         super.onCreate(savedInstanceState);
 8         setContentView(R.layout.activity_main);
 9         
10         textView = (TextView)findViewById(R.id.textView) ;
11     }
12 
13     @Override
14     public boolean onCreateOptionsMenu(Menu menu)
15     {
16         //加载菜单布局文件
17         MenuInflater inflator=new MenuInflater(this);
18         inflator.inflate(R.menu.my_menu, menu);
19         //调用自定义的方法,设定可以显示图标
20         setIconEnable(menu, true);  
21                  
22         return super.onCreateOptionsMenu(menu);
23     }
24 
25     @Override
26     // 选项菜单的菜单项被单击后的回调方法
27     public boolean onOptionsItemSelected(MenuItem mi)
28     {
29         //在这个方法中应该实现菜单项单击事件的响应,通过判定mi.getItemId()的返回值,来断定
30         //当前被单击的菜单项,之后进行具体的业务的处理
31         int id = mi.getItemId();
32         switch(id){
33         case R.id.item_1 :
34             textView.setText("发起群聊选项被单击");
35             break;
36         case R.id.item_2 :
37             textView.setText("创建社区选项被单击");
38             break ;
39         case R.id.item_3 :
40             textView.setText("传送文件选项被单击");
41             break;
42         }
43         return true; 
44     }
45     
46     //自定义方法,用反射机制实现图标的显示
47     private void setIconEnable(Menu menu, boolean enable)  
48         {  
49             try   
50             {  
51                 Class<?> clazz = Class.forName("com.android.internal.view.menu.MenuBuilder");  
52                 Method m = clazz.getDeclaredMethod("setOptionalIconsVisible", boolean.class);  
53                 m.setAccessible(true);  
54                   
55                 //MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征)  
56                 m.invoke(menu, enable);  
57                   
58             } catch (Exception e)   
59             {  
60                 e.printStackTrace();  
61             }  
62         }  
63 }

效果:

 

【主题的不同带来的效果】

当我们选用不同的主题的时候,菜单的显示是不同的,看看下面的几种情况吧:

@android:style/Theme.Holo.Light 主题

@android:style/Theme.Light 主题

 当我们按手机上的“功能键”的时候,会在下方出现菜单,这个很拽!

二、下拉式菜单的创建


 创建下拉式菜单也是非常简单的,只要两步:

1、在<item.../>属性中指定   android:showAsAction="always|withText" 属性,那么这个选项对应的菜单项就会显示在ActionBar的上
2、在设置了 android:showAsAction="always|withText" 属性的<item..../> 中嵌套 <menu..../> 元素,从而形成ActionBar上的菜单的下级菜单

废话少说,直接上代码:

my_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.penglee.menu_test.MainActivity" >
 4 
 5     <item
 6         android:title=""    //当下就流行这种只有图标,不显示文字的菜单,你看看微信什么的,都是这样
 7         android:icon="@drawable/item_picture_1"
 8         android:showAsAction="always">
 9         
10         <menu>
11             <item android:id="@+id/item_1"
12                   android:title="发起群聊"/>
13             <item android:id="@+id/item_2"
14                   android:title="创建社区"/>
15             <item android:id="@+id/item_3"
16                   android:title="传送文件"/>
17         </menu>
18         
19       </item>
20     
21     <item
22         android:title=""
23         android:icon="@drawable/item_picture_2"
24         android:showAsAction="always"/>
25     
26     <item
27         android:title=""
28         android:icon="@drawable/item_picture_3"
29         android:showAsAction="always"/>
30 
31 </menu>

效果:

 

三、ActionBar的使用


1、为了将应用程序图标转变为可以点击的图标,可以调用ActionBar的如下方法。

setDisplayHomeAsUpEnabled(boolean showHomeAsUp):设置是否将应用程序图标转变为可点击的图标,并在图标上添加一个向左的箭头。

setDisplayOptions(int options):通过传入int类型常量来控制该ActionBar的显示选项。

setDisplayShowHomeEnabled(boolean showHome):设置是否显示应用程序的图标。

setHomeButtonEnable(boolean enabled):设置是否将应用程序图标转变成可点击的按钮。

2、一旦程序图标的为被单击之后,那么onOptionsItemSelected(MenuItem mi) 就会被回调,并且返回的mi.getItemId()为android.R.id.home , 那么我们就能够添加事件响应了,一般我们都是添加“返回”等事件响应

3、上代码:还是在上面的程序的基础上写的

 1 public class MainActivity extends Activity {
 2     
 3     TextView textView ;
 4     ActionBar actionBar ;
 5     
 6     @Override
 7     protected void onCreate(Bundle savedInstanceState) {
 8         super.onCreate(savedInstanceState);
 9         setContentView(R.layout.activity_main);
10         
11         textView = (TextView)findViewById(R.id.textView) ;
12         actionBar = getActionBar() ;
13         
14         //设置是否显示应用程序图标
15         actionBar.setDisplayShowHomeEnabled(false);
16         //将应用程序图标设置为可点击的按钮
17         actionBar.setHomeButtonEnabled(true);
18         //将应用程序图标设置为可点击的按钮,并在图标上添加左箭头
19         actionBar.setDisplayHomeAsUpEnabled(true);
20 
21         
22     }
23 
24     @Override
25     public boolean onCreateOptionsMenu(Menu menu)
26     {
27         //加载菜单布局文件
28         MenuInflater inflator=new MenuInflater(this);
29         inflator.inflate(R.menu.my_menu, menu);
30         //调用自定义的方法,设定可以显示图标
31         setIconEnable(menu, true);  
32                  
33         return super.onCreateOptionsMenu(menu);
34     }
35 
36     /*
37      * 实际上这个方法能够响应所有的ActionBar中传来的事件
38      * 
39      * **/
40     @Override
41     public boolean onOptionsItemSelected(MenuItem mi)
42     {
43         int id = mi.getItemId();
44         switch(id){
45         case android.R.id.home:   // 当单击了程序的图标所在的位置,那么会返回这个ID
46             textView.setText("程序的图标位置被单击了");
47             break ;
48         case R.id.item_1 :
49             textView.setText("发起群聊选项被单击");
50             break;
51         case R.id.item_2 :
52             textView.setText("创建社区选项被单击");
53             break ;
54         case R.id.item_3 :
55             textView.setText("传送文件选项被单击");
56             break;
57         }
58         return true; 
59     }
60     
61     //自定义方法,用反射机制实现图标的显示
62     private void setIconEnable(Menu menu, boolean enable)  
63         {  
64             try   
65             {  
66                 Class<?> clazz = Class.forName("com.android.internal.view.menu.MenuBuilder");  
67                 Method m = clazz.getDeclaredMethod("setOptionalIconsVisible", boolean.class);  
68                 m.setAccessible(true);  
69                   
70                 //MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征)  
71                 m.invoke(menu, enable);  
72                   
73             } catch (Exception e)   
74             {  
75                 e.printStackTrace();  
76             }  
77         }  
78 }

效果:

 

【关闭与显示ActionBar】

  活动条(ActionBar)是Android3.0的重要更新之一。ActionBar位于传统标题栏的位置,也就是显示屏幕的顶部。ActionBar可显示应用的图标和Activity标题——也就是前面应用的顶部显示的内容。除此之外,ActionBar的右边还可以显示活动项(Action Item)。

      归纳起来,ActionBar提供了如下功能。

  • 显示选项菜单的菜单项(将菜单项显示成Action Item)。
  • 使用程序图标作为返回Home主键或向上的导航操作。
  • 提供交互式View作为Action View。
  • 提供基于Tab的导航方式,可用于切换多个Fragment。
  • 提供基于下拉的导航方式。

没有讲到的功能以后再说  

    启用ActionBar

     Android3.0版本已经默认启用了ActionBar,因此只要在AndroidManifest.xml文件的SDK配置中指定了该应用的目标版本高于11(Android3.0的版本号),那么默认就会启用ActionBar。例如如下配置:

    

  <uses-sdk
        android:minSdkVersion="17" />

     指定该应用程序可以部署在Android4.2平台上,同时兼容Android2.3.3及更高版本。如果Android版本高于Android3.0,该应用将会启用ActionBar。

     如果希望关闭ActionBar,可以设置该应用的主题为Xxx.NoActionBar,例如如下配置片段:

    

<application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.Holo.NoActionBar" >

   上面的粗体字代码指定该应用ActionBar功能。一旦关闭了ActionBar,该Android应用将不再使用ActionBar。

   实际项目中,通常推荐使用代码来控制ActionBar的显示、隐藏,ActionBar提供了如下方法来控制显示隐藏。

  • show():显示ActionBar。
  • hide():隐藏ActionBar。  

   如下实例示范了如何通过代码来控制ActionBar的显示和隐藏。

   该实例的布局文件如下:

复制代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >
  <Button android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:onClick="showActionBar"
      android:text="显示ActionBar"/>
    <Button android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:onClick="hideActionBar"
      android:text="隐藏ActionBar"/>

</LinearLayout>
复制代码

该实例的Activity代码如下:

复制代码
package org.crazyit.helloworld;

import android.os.Bundle;
import android.app.ActionBar;
import android.app.Activity;
import android.view.Menu;
import android.view.View;

public class ActionBarTest extends Activity {
    ActionBar actionBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.action_bar_test);
        //获取该Activity的ActionBar
        //只有当应用主题没有关闭ActionBar时,该代码才返回ActionBar
        actionBar=getActionBar();
    }
    //为“显示ActionBar”按钮定义事件处理方法
    public void showActionBar(View source)
    {
        //显示ActionBar
        actionBar.show();
    }
    //为“隐藏ActionBar”按钮定义事件处理方法
    public void hideActionBar(View source)
    {
        //隐藏ActionBar
        actionBar.hide();
        
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.action_bar_test, menu);
        return true;
    }

}
复制代码

上面的程序中第一行粗体字代码调用了getActionBar()方法获取该Activity关联的ActionBar。接下来就可以调用ActionBar的方法来控制它的显示、隐藏。

 运行上面的程序单击“隐藏ActionBar”按钮,将可以看到如图所示界面。

posted @ 2014-11-29 21:30  RoperLee  阅读(1100)  评论(0)    收藏  举报