菜单的分类

菜单是Android应用中重要且常见的组成部分,从Android3.0开始,android从一个专用的“菜单按钮”转变为提供一个应用栏来呈现常见的用户操作。

主要可以分为三类:选项菜单上下文菜单/上下文操作模式以及弹出菜单。它们的主要区别如下:

  • 选项菜单:Activity的主菜单项,用于放置对应用产生全局影响的操作,如搜索/设置

  • 上下文菜单: 用户长按某一元素时出现的浮动菜单。它提供的操作将影响所选内容,主要应用于列表中的每一项元素(如长按列表项弹出删除对话框)。

  • 上下文操作模式: 在屏幕顶部栏(菜单栏)显示影响所选内容的操作选项,并允许用户选择多项,一般用于对列表类型的数据进行批量操作。

  • 弹出菜单: 以垂直列表形式显示一系列操作选项,一般由某一控件触发,弹出菜单将显示在对应控件的上方或下方。它适用于提供与特定内容相关的大量操作。

使用XML定义Menu

理论上而言,使用XML和Java代码都可以创建Menu。但是在实际开发中,往往通过XML文件定义Menu,这样做有以下几个好处:

  • XML可以可视化菜单结构

  • 菜单内容与应用的逻辑代码分离

  • 可以使用应用资源框架,为不同的平台版本、屏幕尺寸创建最合适的菜单(如对drawablestring等系统资源的使用)

  • 要定义Menu,我们需要在res文件夹下新建menu文件夹,用于存储与Menu相关的所有XML文件。
    该菜单文件的构成元素包括:<menu><item><group>

  • <menu>: 菜单根节点,能够包含一个或多个<item><group>元素,是定义菜单项的容器。

  • <item>: 菜单项节点,用于定义MenuItem,可以嵌套<menu>元素,以便创建子菜单。

  • <group>: <item>元素的不可见容器(可选),可以使用它对菜单项进行分组,使一组菜单项共享可用性和可见性等属性。

XML菜单文件的示例代码如下:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><itemandroid:id="@+id/item_save"android:icon="@drawable/ic_settings"android:title="保存"app:showAsAction="ifRoom"/><itemandroid:id="@+id/item_settings"android:icon="@drawable/ic_settings"android:title="设置"/
</menu>

其中,<item>是我们主要需要关注的元素,它的常见属性如下:

  • android:id:菜单项(MenuItem)的唯一标识
  • android:icon:菜单项的图标(可选)
  • android:title:菜单项的标题(必选)
  • android:showAsAction:指定菜单项的显示方式。常用的有ifRoomneveralwayswithText

showAsAction的取值说明

取值 说明
ifRoom 只有在标题栏中有空间时才将此项放置其中。如果没有足够的空间容纳标记为ifRoom的所有项,标题栏显示不了的菜单项将显示在溢出菜单中
withText 菜单项的文本和图标一起显示,可以将此值与其他值用竖线分隔共同起作用
never 菜单项永远不显示在标题栏,而隐藏在溢出菜单中
always 始终将此菜单项显示在标题栏。除非必须始终显示在标题栏,否则不要使用该值
collapseActionView 将菜单项折叠到一个按钮中,选择按钮展开,一般与ifRoom一起使用

选项菜单

普通选项菜单

要创建选项菜单,首先需要在XML文件中定义各个菜单项,具体代码如下:

XML代码

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><itemandroid:id="@+id/item_download"android:icon="@drawable/ic_downward"android:title="保存"app:showAsAction="ifRoom"/><itemandroid:id="@+id/item_settings"android:icon="@drawable/ic_settings"app:showAsAction="withText"android:title="设置"/>
</menu>

可以看到,我们在XML文件中定义了两个普通的菜单项。同时,每一个<item>都有一个独特的showAsAction属性。

Activity通过重写onCreateOptionsMenu()方法加载创建的XML菜单资源,在此方法中使用MenuInflater类的inflate()方法将XML资源加载到Menu对象。除此之外,还可以使用add()添加菜单项来动态加载菜单项,具体实现如下:

override fun onCreateOptionsMenu(menu: Menu?): Boolean {//加载xml菜单资源var inflater:MenuInflater = menuInflaterinflater.inflate(R.menu.option_menu,menu)//动态加载菜单项menu?.add(Menu.NONE,Menu.FIRST,3,"帮助")?.setIcon(R.drawable.ic_help)//设置菜单添加图标有效setIconsVisible(menu,true)return true}

当用户从选项菜单中选择菜单项时,系统将调用onOptionsItemSelected(),此方法将传递所选的MenuItem对象,通过调用该MenuItem对象的itemId方法获取菜单项的id,具体实现如下:

override fun onOptionsItemSelected(item: MenuItem): Boolean {//处理菜单项的选择return when(item.itemId){R.id.item_download-> {Toast.makeText(this,"下载",Toast.LENGTH_LONG).show()true}R.id.item_settings-> {Toast.makeText(this,"设置",Toast.LENGTH_LONG).show()true}Menu.FIRST -> {Toast.makeText(this,"帮助",Toast.LENGTH_LONG).show()true}else -> super.onOptionsItemSelected(item)}}

运行效果如图所示:

默认情况下,即便在菜单XML文件中定义了android:icon属性,在溢出菜单中图标也不会显示,本案例使用反射的方法获取Menu对象的setOptionalIconsVisible(),调用该方法显示图标icon,具体实现如下:

//使用反射方法显示图标private fun setIconsVisible(menu: Menu?, flag:Boolean){//判断menu是否为空if(menu != null){try {val method:Method = menu.javaClass.getDeclaredMethod("setOptionalIconsVisible", TYPE)//强制使用方法method.isAccessible//调用该方法显示iconmethod.invoke(menu,flag)}catch (e:Exception){e.printStackTrace()}}}

然后将此方法添加到onCreateOptionsMenu()方法的return语句之前即可,具体实现如下:

  override fun onCreateOptionsMenu(menu: Menu?): Boolean {//加载xml菜单资源var inflater:MenuInflater = menuInflaterinflater.inflate(R.menu.option_menu,menu)//动态加载菜单项menu?.add(Menu.NONE,Menu.FIRST,3,"帮助")?.setIcon(R.drawable.ic_help)//设置菜单添加图标有效setIconsVisible(menu,true)return true}

上下文菜单及上下文操作模式

上下文菜单

通常上下文菜单是以浮动菜单的形式呈现的,用户长按(按住)一个支持上下文菜单的View时,菜单将以浮动列表的形式出现(类似于对话框)。 通常用户一次可对一个项目执行上下文操作(比如一个单独的控件或列表中的一项)。
Android提供了两种上下文操作菜单的方法。

  • 使用浮动上下文菜单:当长按某个View时,显示为菜单项的浮动列表。
  • 使用上下文操作模式:在屏幕顶部栏显示上下文操作栏选项。

1.创建浮动上下文菜单操作步骤

(1)注册菜单

通过调用registerForContextMenu()注册与上下文菜单关联的View。如果将ListViewGridView作为参数传入,那么每个列表将会有相同的浮动上下文菜单。

registerForContextMenu(binding.etName)
(2)加载菜单资源

ActivityFragment中实现onCreateContextMenu(),动态加载Menu资源。当注册后的View收到长按事件时,系统将调用此方法。

override fun onCreateContextMenu(menu: ContextMenu?,v: View?,menuInfo: ContextMenu.ContextMenuInfo?) {super.onCreateContextMenu(menu, v, menuInfo)if (v?.id == R.id.et_name){//加载菜单XML资源val inflater:MenuInflater = menuInflaterinflater.inflate(R.menu.context_menu,menu)//动态创建菜单项
//            menu?.add(Menu.NONE,Menu.FIRST,0,"拷贝")
//            menu?.add(Menu.NONE,Menu.FIRST+1,0,"粘贴")
//            menu?.add(Menu.NONE,Menu.FIRST+2,0,"清空")}}
(3)处理菜单项单击事件

ActivityFragment中实现onContextItemSelected(),实现菜单项的单击逻辑。

override fun onContextItemSelected(item: MenuItem): Boolean {return when(item.itemId){R.id.item_copy-> {Toast.makeText(this,item.title,Toast.LENGTH_LONG).show()true}R.id.item_paste-> {Toast.makeText(this,item.title,Toast.LENGTH_LONG).show()true}R.id.item_clear -> {binding.etName.setText("")true}else -> super.onOptionsItemSelected(item)}}

上下文操作模式

上下文操作模式是ActionMode对象的系统实现,当用户长按控件或选中复选框等组件时调用此模式,会在屏幕顶部出现上下文操作栏,显示用户对所选控件执行的操作。

创建上下文操作栏模式的上下文菜单操作步骤

(1)实现ActionMode.Callback接口

在该接口的回调方法中,为上下文操作栏指定操作、响应菜单项的单击事件等。

// 上下文操作模式对象private var actionMode: ActionMode? = null// 实现ActionMode 中 CallBack回调接口val actionModeCallback: ActionMode.Callback = object : ActionMode.Callback {// 创建方法,在启动上下文操作模式startActionMode(Callback)时调用// 在此配置上下文菜单的资源override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean {mode.menuInflater.inflate(R.menu.context_menu, menu)return true}// 在创建方法后进行调用override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {return false}// 菜单项被点击,类似onContextItemSelected()方法override fun onActionItemClicked(mode: ActionMode?, item: MenuItem): Boolean {when (item.itemId) {R.id.item_copy -> Toast.makeText(this@MainActivity, "拷贝", Toast.LENGTH_SHORT).show()R.id.item_paste -> Toast.makeText(this@MainActivity, "粘贴", Toast.LENGTH_SHORT).show()R.id.item_clear -> binding.etName.setText("")else -> {}}return true}// 上下文操作模式结束时被调用override fun onDestroyActionMode(mode: ActionMode?) {actionMode = null}}

该接口的回调方法与选项菜单的回调方法基本相同,只是需要传递与事件相关联的ActionMode对象。onActionItemClicked()方法用于处理菜单项的单击事件,与onContextItemSelected()类似。当系统销毁操作模式时,需要在onDestroyActionMode()方法中将actionMode变量设置为null。

(2)启动上下文操作模式

在用户名的EditView控件的长按事件中调用startActionMode()启动上下文操作模式,具体实现如下:

binding.etName.setOnLongClickListener(View.OnLongClickListener {if (actionMode!=null){return@OnLongClickListener false}actionMode = startActionMode(actionModeCallback)view.isSelectedreturn@OnLongClickListener false})

调用startActionMode()方法返回ActionMode对象,通过该对象响应上下文操作栏的事件。

弹出菜单

PopupMenu是依赖View存在的模态菜单。如果空间足够,它将显示在相应View的下方,否则显示在其上方。

弹出菜单适用于:

  • 为特定内容密切相关的操作提供溢出式菜单;
  • 提供类似Spinner控件,但不保留永久选择的下拉菜单。

弹出菜单操作步骤:

(1)创建菜单资源文件

res/menu目录下创建PopupMenuXML资源文件。

(2)创建并加载弹出菜单

EditText控件的单击事件方法中实例化PopupMenu对象,传递当前上下文对象及绑定的View对象,然后调用MenuInflater.inflate()方法加载菜单XML文件,调用PopupMenusetOnMenuItemClickListener()设置单击菜单项的事件监听器,最后调用show()方法显示菜单。

binding.etPhone.setOnClickListener(View.OnClickListener {//创建弹出菜单对象(最低版本11),第二个参数是绑定的那个viewval popup:PopupMenu = PopupMenu(this,it)//获取菜单填充器val inflater:MenuInflater = popup.menuInflater//填充菜单inflater.inflate(R.menu.popup_menu,popup.menu)//绑定菜单项的单击事件popup.setOnMenuItemClickListener(this)//显示弹出菜单popup.show()})

(3)处理菜单项的OnMenuItemClick事件

MainActivity类实现PopupMenu.OnMenuItemClickListener接口,重写onMenuItemClick()回调方法,当用户选择菜单项时,系统调用onMenuItemClick()进行处理。

 // PopupMenu菜单项的点击事件override fun onMenuItemClick(item: MenuItem?): Boolean {when(item?.itemId){R.id.item_copy -> Toast.makeText(this,"复制...",Toast.LENGTH_SHORT).show()R.id.item_paste -> Toast.makeText(this,"粘贴...",Toast.LENGTH_SHORT).show()else -> {}}return false}

菜单知识点总结(kotlin)相关推荐

  1. 【微信公众号】菜单知识点

    1.微信公众平台新增了个性化菜单接口,开发者可以通过该接口,让公众号的不同用户群体看到不一样的自定义菜单.该接口开放给已认证订阅号和已认证服务号.出于安全考虑,一个公众号的所有个性化菜单,最多只能设置 ...

  2. Kotlin学习笔记 第四章 Java调用Kotlin

    参考链接 Kotlin官方文档 https://kotlinlang.org/docs/home.html 中文网站 https://www.kotlincn.net/docs/reference/p ...

  3. Kotlin学习笔记 第二章 类与对象 第九节 泛型

    参考链接 Kotlin官方文档 https://kotlinlang.org/docs/home.html 中文网站 https://www.kotlincn.net/docs/reference/p ...

  4. Kotlin学习笔记 第一章开始 第二章 基础

    参考链接 Kotlin官方文档 https://kotlinlang.org/docs/home.html 本系列为参考Kotlin中文文档 https://download.csdn.net/dow ...

  5. Kotlin入门(2)让App开发变得更容易

    上一篇文章介绍了如何搭建Kotlin的开发环境,可是这个开发环境依然基于Android Studio,而在Android Studio上使用Java进行编码,本来就是理所应当的,何必还要专门弄个Kot ...

  6. 《Kotlin从小白到大牛》第28章:项目实战1:开发PetStore宠物商店项目

    第28章 项目实战1:开发PetStore宠物商店项目 前面学习的Kotlin知识只有通过项目贯穿起来,才能将书本中知识变成自己的.通过项目实战读者能够了解软件开发流程,了解所学知识在实际项目中使用的 ...

  7. Kotlin中Int和 Int? 以及 IntArray 和 Array的问题

    开篇 之前文章中提到过,kotlin 的形参如果不加?那么会默认为不为空. 这个小知识点在 kotlin 编译的时候其实很有用的,我们拿java中的 int和 Integer 来举例. Integer ...

  8. 开发你的第一个 Android 应用

    题图 | Technology vector created by stories - www.freepik.com 以下内容节选自经典权威 Android 入门与进阶图书 <Android编 ...

  9. 继往开来:Google I/O 21 Android Gradle Plugin 更新总结

    距离 Google I/O 2021 已经过去了将近一个月,最近几天捋了捋关于 Android Gradle Plugin(AGP)方面的东西,主要集中在 "What's new in An ...

  10. 豆瓣评分 8.6,近 5 万读者学习的 Android 经典最新版出版,承载无数程序员的回忆......

    题图 | 新的小绿人 © Google "出色向导" 对新手来说,学习 Android 开发一开始会很难.就像初次踏入异国他乡一样,即使会说当地语言,一开始也绝不会有舒服自在的感觉 ...

最新文章

  1. 怎么自学python语言-怎样学好python
  2. 测验8: 程序设计方法学 (第8周)
  3. 现在有一个整数数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数...
  4. Nginx基本数据结构之ngx_hash_t
  5. Table边框使用总结
  6. matlab的和操作
  7. pppoe 服务器 无线,centos搭建pppoe拨号服务器
  8. XManager连接CentOS6.5
  9. timestamp显示毫秒_TimeStamp 毫秒和纳秒
  10. 题5 正确的Java垃圾回收说法
  11. linux 没有network服务,求助,network起不来
  12. android短信验证码登录,Android注册登录实时自动获取短信验证码
  13. idea中的常用快捷键(新手必看)
  14. 【总结】线性代数的本质 - 3
  15. mysql导入excel表_mysql怎么导入excel数据?
  16. photon四种同步方式_Photon——主从服务器负载均衡及策略
  17. 赛意SMOM和金蝶云星空单据接口对接
  18. 2014年3I工作室成员的正式名单
  19. 修复柱面要多少时间_宜昌平面设计培训多少钱大约要学习多长时间
  20. 【计算机视觉】图片拼接

热门文章

  1. 蓝桥杯——公交汽车(完全背包-动态规划)
  2. 23考研-西南大学计算机学院-电子信息-907-初试经验贴
  3. 日照申请著作权有以下几点好处
  4. DeFi 玩家收益农耕的五种形式
  5. 王飞跃:技术发展的问题,应该靠发展技术来解决
  6. 从零开始的知识巩固(【2021】2.java基础进阶篇)
  7. 基于中国剩余定理的秘密共享方案(python)实现
  8. php一个网站怎么做多国语言,网站国际化多语言版本怎么做啊?
  9. 文华指标源码—扑捉顶底
  10. stm32串口学习笔记(参考原子哥以及野火哥)