作为 Android 用户,你一定见过类似这样的页面:
它就是我们今天的主角——菜单,它的使用场景和作用不用多说,几乎每个 App 都会用到它,今天我们就一起来看看 Android 提供的几种菜单类型及用法。
1. 菜单的几种类型
根据不同的业务场景和不同的样式,Android 提供了以下 3 种菜单:
- Option Menu: 选项菜单
- Context Menu: 上下文菜单
- Pop-up Menu: 弹窗菜单
下面来分别介绍这 3 种菜单类型
1.1 Option Menu
选项文菜单是最常用的 Menu,可以直接通过 Android 的“菜单键”唤出,通常直接为当前 Activity 服务。在高版本的 Android 系统上是从右上角弹出,可以在里面放置一些常用的功能入口或者设置项等等高频选项。
1.2 Context Menu
上下文菜单需要绑定在一个控件之上,当我们长按这个控件的时候就会出现一个悬浮窗式的菜单,通常用于设置某个控件的属性或内容。
1.3 Popup Menu
从字面上看和上一节学的 PopupWindow 很像,没错,它的样式确实和 PopupWindow 是一样一样的。同时它也需要绑定到一个 View 上面,然后会以一个竖直列表的形式弹出一个悬浮窗,非常适合对 View 进行设置或者提供一些相关的附加选项。
注意: Context Menu 和 Popup Menu 都需要和一个 View 绑定,但 Popup Menu 里面的选项点击不应该直接影响到 View的内容,否则应该使用 Context Menu,Popup Menu 更多的是用于 View 相关操作的扩展。
2. Menu 资源的创建方法
对于以上提到的 3 种类型的菜单,你都可以通过 Java 代码或者 XML 资源文件两种方式创建,但大多数情况下我强烈推荐使用XML 的形式。用 XML 可以对菜单结构一目了然,并且和逻辑代码物理隔离,更有利于我们维护。在编写完 XML 菜单资源之后,在 Java 代码中直接 inflate 加载资源文件即可。
创建菜单资源需要以下步骤:
- 右键点击“res”目录,依次选择:new -> Android resource directory ,如下:
- 在弹出的窗口中输入“menu”并选择 Resource Type 为“menu”,点击 OK:
- 右键点击“menu”文件夹,依次选择“New -> Menu resource file”,在 menu 目录新增一个名为“menu.xml”的菜单资源:创建完成之后,就可以开始编写 menu.xml 文件了,一个菜单资源文件通常包含以下标签:
-
menu:
必选标签。用来定义一个菜单,菜单内所有的选项(item)都需要写在<menu/>
标签内,同时它也是整个 menu 资源文件的根节点。 -
item:
必选标签。用来创建一个菜单项,每一个<item/>
标签代表 menu 中的一个选项,另外在<item/>
中我们还可以嵌套定义<menu/>
节点,以此来创建一个子菜单。 -
group:
可选标签。用来将多个<item/>
标签做分组,它用来对菜单里的选项进行分类,这样同类型的选项可以共享一些属性,增强选项类别。
在了解了菜单资源标签之后,我们就可以简单编写一个菜单资源了,代码非常简单如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/main_menu"
android:title="我要学习客户端开发"
android:icon="@drawable/ic_launcher" >
<!-- 添加客户端子菜单 -->
<menu>
<item android:id="@+id/submenu1"
android:title="学习 Android"
android:icon="@drawable/ic_launcher"/>
<item android:id="@+id/submenu2"
android:title="学习 iOS"
android:icon="@drawable/apple" />
</menu>
</item>
</menu>
其中<item/>
标签支持几种属性来配置样式或者行为,常用的属性比较好理解,主要有以下 2 种:
- android:id:
菜单项的资源 ID,用来唯一标识某个选项,后续可以通过 ID 来判断用户点击的是哪个菜单项。 - android:icon:
设置菜单项对应的图标 - android:title:
设置菜单项的内容
3. 几种菜单的使用
在第 2 小节我们已经通过 XML 的形式完成了菜单内容的设置,接着需要在 Activity 中编写逻辑并加载菜单资源,以下就根据不同的类型分别演示如何完成菜单的加载及使用。
3.1 Option Menu 示例
3.1.1 加载 Option Menu 资源
为了使用 Option Menu,我们需要在 Activity 中复写onCreateOptionsMenu()
方法:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_file, menu);
return true;
}
当 Activity 创建 Option Menu 的时候系统会回调此函数,我们只需要在里面 inflate 我们的菜单资源即可,其中getMenuInflater()
用来获取一个“MenuInflater”对象,我们可以用它来加载一个 menu 资源文件——menu.xml。
3.1.2 处理菜单项的点击事件
当用户在菜单中点击了某个选项之后,Android 系统会回调onOptionsItemSelected()
方法,并传入被选菜单项的 Menu 实例。我们可以通过 Menu 实例的getItemId()
方法拿到菜单项对应的唯一 ID(通过<item/>
标签的 android:id 属性设置的),从而判断用户选择的是哪一项,进而执行相应的逻辑,代码如下:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// 根据点击的选项处理不同的逻辑
switch (item.getItemId()) {
case R.id.menu:
// 点击主菜单
return true;
case R.id.submenu1:
// 点击子菜单1
return true;
case R.id.submenu2:
// 点击子菜单2
return true;
default:
return super.onOptionsItemSelected(item);
}
}
**注意:**在你成功处理了菜单项的点击事件之后(我们通常称之为消费),你需要在函数的末尾返回“true”,如果没有消费那么可以返回false,不过建议调用
super.onOptionsItemSelected(item)
将本次点击事件交给上层处理(上层的默认实现也是false)。
3.2 Context Menu 示例
3.2.1 加载 ContextMenu
加载一个 ContextMenu 通常需要以下步骤:
- 调用
registerForContextMenu()
传入一个 View,来为该 View 注册一个Context Menu,从此该 View 就和一个 OptionMenu 绑定; - 在 Activity 中复写
onCreateContextMenu()
方法,当用户长按你注册过的 View,Android 系统就会回调此方法,我们可以在这里进行 menu 资源的加载。
其实逻辑和 Option Menu 类似,但是因为需要绑定 View 所以多了一个注册操作,加载代码如下:
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_file, menu);
}
onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
方法需要传入 3 个参数,分别是:
- ContextMenu menu: 菜单对象,类似 OptionMenu 里面的 Menu 对象
- View v: 与 Context Menu 绑定的 View 对象
- ContextMenuInfo menuInfo: 包含与被选项的一些附加信息
注意: 如果当前 Activity 有多个 View 都有 Context Menu,那么需要通过这几个参数来判断当前触发的是哪个 View 相关的 Context Menu
3.2.2 处理 Context Menu 选项的点击事件
当用户点击上下文菜单项的时候,系统会回调onContextItemSelected()
方法,所以我们可以在方法里实现相应的处理逻辑。如下:
@Override
public boolean onContextItemSelected(MenuItem item) {
// 处理 Context Menu 选项的点击事件
}
}
3.3 Popup Menu 示例
3.3.1 展示 Popup Menu
和 Context Menu 类似,Popup Menu 也需要和一个 View 绑定,但二者的加载过程有些不同。加载一个 Popup Menu 需要经过 3 个步骤:
- 调用 PopupMenu 的构造器,传入当前 Application 的上下文对象,待绑定的 View;
- 调用
getMenuInflater()
获取 MenuInflater对象,通过它将菜单资源装载入 PopupMenu 的 Menu 实例中; - 调用 PopupMenu 对象的
show()
弹出菜单。
加载代码如下:
PopupMenu popupMenu = new PopupMenu(this,view);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu,popupMenu .getMenu());
popup.show();
3.3.2 监听 Popup Menu 的点击事件
为了监听 Popup Menu 的点击事件,我们需要在 Activity 中实现PopupMenu.OnMenuItemClickListener
接口并通过setOnMenuItemclickListener()
方法注册 Popup Menu。这样一来,当用户点击菜单项的时候,Android 系统会回调 Activity 的onMenuItemClick()
方法,在当中处理点击事件即可。
4. 完整示例代码
通过以上针对每个类型 Menu 的讲解,大家对菜单的创建和使用应该都比较清楚了,下面我们通过一个完整的示例来演示一下 3 种菜单的使用。
4.1 编写 menu 资源
在第 2 小节中我们详细介绍了 menu 资源,它包括<menu/>
、<item/>
、<group/>
三种标签,为了演示方便我们直接采用第 2 小节中的菜单资源。
4.2 编写布局
菜单本身并不涉及到布局的编写,我们只需要两个 View,一个绑定给 Context Menu,一个给 Popup Menu:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_context"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="30dp"
android:text="我这里有 Context Menu"
android:textSize="20sp" />
<Button
android:id="@+id/bt_popup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="pop"
android:text="我这里有 Popup Menu" />
</LinearLayout>
4.3 编写 Activity
最后就可以编写 Activity 了,其中要做的就是为 Menu 做资源加载,并接收点击回调即可:
package com.emercy.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.PopupMenu;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivityimplements PopupMenu.OnMenuItemClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 为 TextView 注册 Context Menu
registerForContextMenu(findViewById(R.id.tv_context));
}
// 加载 Option Menu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu, menu);
return true;
}
// 接收 Option Menu 的点击
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return onItemClick(item);
}
// 加载 Context Menu
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu, menu);
}
// 接收 Context Menu 的点击
@Override
public boolean onContextItemSelected(MenuItem item) {
return onItemClick(item);
}
// 加载 Popup Menu
public void pop(View v){
PopupMenu popup = new PopupMenu(this, v);
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu, popup.getMenu());
popup.show();
}
// 接收 Popup Menu 的点击
@Override
public boolean onMenuItemClick(MenuItem item) {
return onItemClick(item);
}
private boolean onItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.main_menu:
Toast.makeText(this, "选择了客户端开发", Toast.LENGTH_SHORT).show();
break;
case R.id.submenu1:
Toast.makeText(this, "选择学习 Android", Toast.LENGTH_SHORT).show();
break;
case R.id.submenu2:
Toast.makeText(this, "选择学习 iOS", Toast.LENGTH_SHORT).show();
break;
}
return true;
}
}
针对每个菜单都分别有“加载资源”和“处理点击”两种操作,另外由于每个菜单的处理逻辑都一样,为了增强代码复用性我单独拎出了一个函数onItemClick()
专门用于统一处理点击事件。
最终样式如下(在不同的设备上可能会有所不同):
Option Menu 的子菜单:
Context Menu 的子菜单:
Popup Menu 的主菜单:
5. 小结
本节介绍了 Android 提供的几种菜单:Option Menu 通常用来提供 Activity 相关的选项,Context Menu 通常用来针对某个 View 进行设置,而 Popup Menu 用来设置某个 View 的属性或者展示一些附加功能。使用的步骤大体相同,在一个完整 App 的开发中,Menu 是必不可少的部分,希望大家能够很好的掌握本节内容。