34. 【Android教程】菜单:Menu

作为 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

上下文菜单需要绑定在一个控件之上,当我们长按这个控件的时候就会出现一个悬浮窗式的菜单,通常用于设置某个控件的属性或内容。

从字面上看和上一节学的 PopupWindow 很像,没错,它的样式确实和 PopupWindow 是一样一样的。同时它也需要绑定到一个 View 上面,然后会以一个竖直列表的形式弹出一个悬浮窗,非常适合对 View 进行设置或者提供一些相关的附加选项。

注意: Context Menu 和 Popup Menu 都需要和一个 View 绑定,但 Popup Menu 里面的选项点击不应该直接影响到 View的内容,否则应该使用 Context Menu,Popup Menu 更多的是用于 View 相关操作的扩展。

对于以上提到的 3 种类型的菜单,你都可以通过 Java 代码或者 XML 资源文件两种方式创建,但大多数情况下我强烈推荐使用XML 的形式。用 XML 可以对菜单结构一目了然,并且和逻辑代码物理隔离,更有利于我们维护。在编写完 XML 菜单资源之后,在 Java 代码中直接 inflate 加载资源文件即可。

创建菜单资源需要以下步骤:

  1. 右键点击“res”目录,依次选择:new -> Android resource directory ,如下:
  2. 在弹出的窗口中输入“menu”并选择 Resource Type 为“menu”,点击 OK:
  3. 右键点击“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()方法:

@Overridepublic 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:// 点击子菜单1return true;case R.id.submenu2:// 点击子菜单2return true;default:return super.onOptionsItemSelected(item);}
}

**注意:**在你成功处理了菜单项的点击事件之后(我们通常称之为消费),你需要在函数的末尾返回“true”,如果没有消费那么可以返回false,不过建议调用super.onOptionsItemSelected(item)将本次点击事件交给上层处理(上层的默认实现也是false)。

3.2 Context Menu 示例

3.2.1 加载 ContextMenu

加载一个 ContextMenu 通常需要以下步骤:

  1. 调用registerForContextMenu()传入一个 View,来为该 View 注册一个Context Menu,从此该 View 就和一个 OptionMenu 绑定;
  2. 在 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()方法,所以我们可以在方法里实现相应的处理逻辑。如下:

@Overridepublic boolean onContextItemSelected(MenuItem item) {// 处理 Context 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" ><TextViewandroid:id="@+id/tv_context"android:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingBottom="30dp"android:text="我这里有 Context Menu"android:textSize="20sp" /><Buttonandroid: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 {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 为 TextView 注册 Context MenuregisterForContextMenu(findViewById(R.id.tv_context));}// 加载 Option Menu@Overridepublic boolean onCreateOptionsMenu(Menu menu) {MenuInflater menuInflater = getMenuInflater();menuInflater.inflate(R.menu.menu, menu);return true;}// 接收 Option Menu 的点击@Overridepublic boolean onOptionsItemSelected(MenuItem item) {return onItemClick(item);}// 加载 Context Menu@Overridepublic 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 的点击@Overridepublic boolean onContextItemSelected(MenuItem item) {return onItemClick(item);}// 加载 Popup Menupublic void pop(View v){PopupMenu popup = new PopupMenu(this, v);MenuInflater menuInflater = getMenuInflater();menuInflater.inflate(R.menu.menu, popup.getMenu());popup.show();}// 接收 Popup Menu 的点击@Overridepublic 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 是必不可少的部分,希望大家能够很好的掌握本节内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/827.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何实现文件上传到阿里云OSS!!!(结合上传pdf使用)

一、开通阿里云OSS对象存储服务 对象存储 OSS_云存储服务_企业数据管理_存储-阿里云阿里云对象存储 OSS 是一款海量、安全、低成本、高可靠的云存储服务&#xff0c;提供 99.995 % 的服务可用性和多种存储类型&#xff0c;适用于数据湖存储&#xff0c;数据迁移&#xff0c;企…

数据结构- 顺序表-单链表-双链表 --【求个关注!】

文章目录 一 顺序表代码&#xff1a; 二 链表单链表双向链表 一 顺序表 顺序表是线性表的一种 所谓线性表指一串数据的组织存储在逻辑上是线性的&#xff0c;而在物理上不一定是线性的 顺序表的底层实现是数组&#xff0c;其由一群数据类型相同的元素组成&#xff0c;其在逻辑…

「Word 论文排版」插入分节符导致word转PDF后出现空白页

问题 word转PDF后出现空白页 解决 但是此方法会让页面页脚标记出错 TODO 如下图所示 在论文目录后有一个分节符&#xff0c;转成PDF之后就多了一个空白页 文件-打印-页面设置-选中封面那一页-版式-从偶数页开始 再导出空白页就没了

Java编程题 | 数组元素交换

大家可以关注一下专栏&#xff0c;方便大家需要的时候直接查找&#xff0c;专栏将持续更新~ 题目描述 编写一个Java程序&#xff0c;输入一个整数数组&#xff0c;将最大的元素与第一个元素交换&#xff0c;最小的元素与最后一个元素交换&#xff0c;然后输出修改后的数组…

香港多IP服务器在建立高可用性网站架构中的作用?

香港多IP服务器在建立高可用性网站架构中的作用&#xff1f; 在构建高可用性的网站架构时&#xff0c;选择合适的服务器和配置是至关重要的。香港多IP服务器因其独特的地理和技术优势&#xff0c;成为了全球许多企业的首选。这些服务器由于拥有多个IP地址&#xff0c;能够提供…

OpenHarmony多媒体-mp3agic

简介 mp3agic 用于读取 mp3 文件和读取/操作 ID3 标签&#xff08;ID3v1 和 ID3v2.2 到 ID3v2.4&#xff09;,协助开发者处理繁琐的文件操作相关&#xff0c;多用于操作文件场景的业务应用。 效果展示&#xff1a; 下载安装 ohpm install ohos/mp3agicOpenHarmony ohpm环境配…

Docker Desktop打开一直转圈的解决办法

安装Docker Desktop之前确保你的Hyper-V已经打开 开启后需要重新安装重新安装重新安装这是最关键的一步&#xff0c;博主自己看了很多教程&#xff0c;最后试着重装了一下解决了 安装DockerDesktop的时候我的电脑根本就没有Hyper-V这个功能选项&#xff0c;可能是这个问题 如…

域名信息查询同款WHOIS源码

域名查询一般是指查询域名的whois注册信息&#xff0c;域名WHOIS是当前域名系统中不可或缺的一项信息服务。在使用域名进行Internet冲浪时&#xff0c;很多用户希望进一步了解域名、名字服务器详细信息 源码免费下载地址抄笔记 (chaobiji.cn)https://chaobiji.cn/

力扣打卡第一天

101. 对称二叉树 C&#xff1a; class Solution { public:bool isSymmetric(TreeNode* root) {return check(root->left,root->right);}bool check(TreeNode *p,TreeNode *q){ /**定义check方法用来检查两棵树是否是镜像的*/if (!p && !q) return true; /* 如…

鸿蒙开发语言_ArkTS开发语言体验_TypeScript语言环境搭建_TS声明和数据类型---HarmonyOS4.0+鸿蒙NEXT工作笔记003

可以看到我们新建的这个项目,有个 @State message: String =Hello ArkTS 这个就是定义了一个变量,可以看到 message是变量名,String是变量类型. 然后我们可以看看它的结构可以看到 build() 下面有个Row,然后再下面有个Column方法,然后,里面就是具体的内容了,首先就是显示了一…

Python数据结构【四】排序(二)难度:困难

文章目录 前言一、书接上回二、快速排序&#xff08;Quick Sort&#xff09;2.1 快速排序思想2.2 快速排序代码实现2.3 快速排序复杂度分析 三、堆排序&#xff08;Heap Sort&#xff09;3.1 堆排序思想3.2 堆排序代码实现3.3 堆排序复杂度分析 结语 前言 可私聊进一千多人Pyth…

文件名批量改名,高效将文件名里的符号进行替换删除掉,实现文件名的高效管理

在信息爆炸的时代&#xff0c;我们每天都在与大量的文件打交道。从工作文档到个人照片&#xff0c;从视频剪辑到音频录音&#xff0c;每个文件背后都承载着我们的辛勤付出和美好回忆。然而&#xff0c;随着文件数量的不断增加&#xff0c;如何高效管理这些文件成为了一个亟待解…

MongoDB安装及集成

MongoDB安装及集成 前言 MongoDB是一个开源的、面向文档的 NoSQL 数据库&#xff0c;它采用了 JSON 风格的文档来存储数据&#xff0c;而不是传统的表格形式。MongoDB在数据存储方面具有灵活性和可扩展性&#xff0c;使得它成为了当今流行的数据库之一。 MongoDB的主要特点和…

关于ERA5气压和温度垂直补偿公式的对比情况

1. 气压和温度垂直补偿对比 「谨代表给个人观点&#xff0c;杠精请自测&#xff0c;对对对&#xff0c;好好好&#xff0c;你说啥都对」。 使用2020-2022陆态网GNSS与探空站并址的48个站点实验&#xff0c;以探空站为真值&#xff0c;验证ERA5精度。怎么确定并址请看前面文章…

C++感受6-Hello World 交互版

变量、常量输入、输出、流getline() 函数读入整行输入Hello() 函数复习新定义函数 Input() 实现友好的人机交互还有 “痘痘” 为什么挤不到的分析…… 1. DRY 原则简介 上一节课&#xff0c;我们写了两版“问候”程序。第一版的最大问题是重复的内容比较多&#xff0c;每一次问…

webAssembly学习及使用rust

学习理解 webAssembly 概念知识&#xff0c;使用 API 进行 web 前端开发。 概念 是一种运行在现代网络浏览器中的新型代码&#xff0c;并且提供新的性能特性和效果。它有一种紧凑的二进制格式&#xff0c;使其能够以接近原生性能的速度运行。C/C、 C#、Rust等语言可以编译为 …

RIP小实验配置及缺省路由下发

配置如下&#xff1a; IP配置&#xff1a; IP配置完先查看RIP协议学习到的路由表&#xff0c;没有内容则代表没有开启RIP 启用RIP&#xff1a;这里的rip后跟的ID只具有本地意义&#xff0c;可以在1-65535之间随便取&#xff0c;不同路由器之间都可以取用不同的&#xff0c;为了…

上网行为管理系统功能介绍_上网行为管理实现的功能

上网行为管理系统是一种集成了网络监控、行为分析、策略管理和安全控制等功能的综合性软件解决方案。 它通过对企业内部网络的全面监控和深度分析&#xff0c;帮助管理者了解员工的网络使用习惯、识别潜在风险、优化网络资源配置&#xff0c;并最终实现网络安全和效率的双重提…

对接浦发银行支付(三)-- QR扫码付

一、使用场景 扫码付&#xff0c;指的是支付平台&#xff0c;给每个用户的具体订单生成一个QR二维码&#xff0c;用户本人或者他人扫码付款。 付款用户可以直接识别二维码&#xff0c;或者下载到本地&#xff0c;通过微信或支付宝扫一扫识别&#xff0c;第二步将跳转至对应的支…

详细分析Java中的AuthRequest类(附Demo)

目录 前言1. 基本知识2. Demo3. 实战 前言 公共接口&#xff0c;定义了对第三方平台进行授权、登录、撤销授权和刷新 token 的操作 1. 基本知识 先看源码基本API接口&#xff1a; import me.zhyd.oauth.enums.AuthResponseStatus; import me.zhyd.oauth.exception.AuthExce…