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”按钮,将可以看到如图所示界面。



浙公网安备 33010602011771号