1. 需求描述

Android Menu菜单是比较常见的功能,在ActionBar  or ToolBar上显示,点击更多(3个点),会有下拉列表菜单展示,  在工作项目中有个小需求改动: 在 ToolBar上添加一个图标,点击后会切换图标状态,界面也会显示对应内容,这也是本篇文章要讲的是如何动态更新Menu菜单。

首先,我们来看看效果图:

1. 当点击网格图标时,显示为网格模式

2. 当点击列表图标时,显示为列表模式

3. 点击更多图标时,显示更多菜单列表:设置   关于  测试

2. 基础知识

在写代码之前,先来复习一下Menu的基础知识,具体可以看官方文档:Menus  |  Android Developers

菜单xml编写例子:

<menu 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"tools:context="com.example.menutest.MainActivity"><itemandroid:id="@+id/sub_menu_grid"android:title="网格视图"android:icon="@drawable/ic_menu_view_grid"app:showAsAction="always"/><itemandroid:id="@+id/sub_menu_list"android:title="列表视图"android:icon="@drawable/ic_menu_view_list"app:showAsAction="always"/><itemandroid:id="@+id/action_settings"android:orderInCategory="100"android:title="设置"app:showAsAction="never" /><itemandroid:id="@+id/action_about"android:orderInCategory="200"android:title="关于"app:showAsAction="never" /><itemandroid:id="@+id/action_test"android:orderInCategory="300"android:title="测试"app:showAsAction="never" /></menu>

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

android:id:     菜单项(MenuItem)的唯一标识(必须定义)
    android:icon: 菜单项的图标(可选)
    android:title: 菜单项的标题(必选)
    android:showAsAction:指定菜单项的显示方式。常用的有ifRoom、never、always、withText,多个属性值之间可以使用|隔开。

指定菜单的显示方式:

always:菜单项永远不会被收纳到溢出菜单中,因此在菜单项过多的情况下可能超出菜单栏的显示范围。

ifRoom:在空间足够时,菜单项会显示在菜单栏中,否则收纳入溢出菜单中。

withText:无论菜单项是否定义了icon属性,都只会显示它的标题,而不会显示图标。使用这种方式的菜单项默认会被收纳入溢出菜单中。

never:菜单项永远只会出现在溢出菜单中。

我们通过上面的3张图片,在Toolbar上面显示有两类菜单:

1. 比如网格和列表菜单,在菜单栏上定义为一直显示(always),我们称它为常驻菜单

2. 另一种会被集中放置到溢出菜单中(就是菜单栏右侧的3个小点图标图标)

3. 菜单加载

菜单加载,有两个相关API

1.  onCreateOptionsMenu(Menu menu)

此方法在初次加载菜单时,会调用一次。

2.  onPrepareOptionsMenu(Menu menu)

此方法应用场景:在运行时更改菜单项,我们看看官网的描述:

在运行时修改的选项菜单:

系统调用onCreateOptionsMenu方法后,将保留创建的Menu实例。除非菜单由于某些原因而失效,否则不会再次调用onCreateOptionsMenu。因此,我们只应该使用onCreateOptionsMenu来创建初始菜单状态,而不应使用它在Activity生命周期中对菜单执行任何更改。

如果需要根据在Activity生命周期中发生的某些事件修改选项菜单,则应该通过onPrepareOptionsMenu方法实现。这个方法的参数中有一个Menu对象(即旧的Menu对象),我们可以使用它对菜单执行修改,如添加、移除、启用或禁用菜单项。(Fragment同样提供onPrepareOptionsMenu方法,只是不需要提供返回值)

需要注意:在Android 3.0及更高版本中,当菜单项显示在应用栏中时,选项菜单被视为始终处于打开状态,说的就是常驻菜单。发生事件时,如果要执行菜单更新,则必须调用 invalidateOptionsMenu来请求系统调用onPrepareOptionsMenu方法

对于上句话我的理解如下:

1. 对于常驻菜单,如果你想动态修改菜单的话,就必须调用 invalidateOptionsMenu() 方法去更新,为什么呢? 因为调用 invalidateOptionsMenu方法后,会重新执行一遍 onCreateOptionsMenu 和 onPrepareOptionsMenu这两个方法。

2. 对于溢出菜单,如果你想动态修改菜单的话,只需要在onPrepareOptionsMenu方法中实现即可,为什么呢?

当你点击 更多(3个小点)图标的时候,就会回调onPrepareOptionsMenu方法

4. 需求实现

有了上面理论做支持,具体结合需求,网格和列表菜单属于常驻菜单,所以必须先要调用invalidateOptionsMenu()方法,然后在onPrepareOptionsMenu去写动态更新状态的代码

图三中,关于属于溢出菜单,需求: 关于 菜单不能点击,所以也是在onPrepareOptionsMenu中去写动态更新状态的代码

好了,我把代码展示出来:

public class MainActivity extends AppCompatActivity {//默认为网格模式private boolean isShowGridModeIcon = true;//网格菜单 和 列表菜单private MenuItem gridMenuItem;private MenuItem listMenuItem;//用字符串来表示当前的文件列表显示模式private TextView viewModeStatus;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Toolbar toolbar = findViewById(R.id.toolbar);setSupportActionBar(toolbar);viewModeStatus = findViewById(R.id.textview_refresh);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.menu_main, menu);Log.e("test", "=====MenuTest onCreateOptionsMenu=====");gridMenuItem = menu.findItem(R.id.sub_menu_grid);listMenuItem = menu.findItem(R.id.sub_menu_list);return true;}@Overridepublic boolean onPrepareOptionsMenu(Menu menu) {Log.e("test", "=====MenuTest onPrepareOptionsMenu=xxxx====");MenuItem aboutMenuItem = menu.findItem(R.id.action_about);// (3个点)【更多】菜单中把 关于 设置为不可点击aboutMenuItem.setEnabled(false);if (isShowGridModeIcon) {gridMenuItem.setVisible(true);listMenuItem.setVisible(false);viewModeStatus.setText("当前为网格模式");} else {gridMenuItem.setVisible(false);listMenuItem.setVisible(true);viewModeStatus.setText("当前为列表模式");}return super.onPrepareOptionsMenu(menu);}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();Log.e("test", "=====MenuTest onOptionsItemSelected= sssss ====");//noinspection SimplifiableIfStatementif (id == R.id.action_settings) {return true;} else if (id == R.id.sub_menu_grid) {/*1. 点击网格图标,界面中文件布局显示变成网格模式*///伪代码:setViewMode(State.MODE_GRID);isShowGridModeIcon = false;/*2. 图标变成切换list图标*/invalidateOptionsMenu();} else if (id == R.id.sub_menu_list) {/*1.点击列表图标,界面中文件布局显示变成列表模式*///伪代码:setViewMode(State.MODE_LIST);isShowGridModeIcon = true;/*2. 图标变成切换grid图标*/invalidateOptionsMenu();}return super.onOptionsItemSelected(item);}
}

代码中加了打印log
1.  在桌面上启动apk的时候,打印log如下:

21900 21900 E test    : =====MenuTest onCreateOptionsMenu=====
21900 21900 E test    : =====MenuTest onPrepareOptionsMenu=xxxx====

2. 点击网格模式菜单时,打印log如下:

21900 21900 E test    : =====MenuTest onOptionsItemSelected= sssss ====
21900 21900 E test    : =====MenuTest onCreateOptionsMenu=====
21900 21900 E test    : =====MenuTest onPrepareOptionsMenu=xxxx====

如上分析,在onOptionsItemSelected方法中点击响应时,调用了invalidateOptionsMenu方法,所以会重新走一遍onCreateOptionsMenu, onPrepareOptionsMenu。

3. 点击(3个点)更多菜单时,打印log如下:

21900 21900 E test    : =====MenuTest onPrepareOptionsMenu=xxxx====

如上分析, 对于溢出菜单类型,点击更多菜单时,只会回调onPrepareOptionsMenu方法

5. 总结

本篇文章讲解了动态菜单更新显示的过程,也是对menu菜单的一个小结,对于同类需求,可以仿照此demo,整个Demo代码我上传到这里:Android动态更新Menu菜单-Android文档类资源-CSDN下载

Android 动态更新Menu菜单相关推荐

  1. android 实现表格横向混动_Flutter混合开发和Android动态更新实践

    Flutter混合开发和Android动态更新实践 感谢闲鱼和csdn的文章给的思路: 本篇是实践性文章包含两部分 将Flutter工程编译后的文件集成到Android项目 将Flutter代码热更新 ...

  2. android 动态更新配置文件,基于DX的Android动态更新技术

    原标题:基于DX的Android动态更新技术 转自:文/Mob开发者平台 技术副总监 余勋杰 DX简介 安卓程序的主要代码是java 代码,不过由于安卓系统不直接使用sun的jvm,所以从javac编 ...

  3. android 自定义menu 背景颜色,Android中设置Menu菜单的文字颜色为白色

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 开发者交流裙: 188168040 Android中设置Menu菜单的文字颜色为白色,一般情况下,Android中Menu菜单的title文字颜色为黑色, ...

  4. Unity Android 动态更新 Assembly-CSharp.dll

    http://blog.sina.com.cn/s/blog_9e5d42ee0102vvtg.html 1.流程 游戏启动后先加载包里面的Assembly-CSharp.dll --> 在sp ...

  5. android更改menu字体颜色,Android动态修改menu颜色

    昨晚有人在群里问怎么动态修改menu的颜色 关键对方还说在网上百度了3个小时了,依然没有解决问题 我知道,轮到我出手了

  6. Android学习笔记--Menu菜单的使用

    实现选项菜单.上下文菜单,以及菜单内部的子菜单. 视图效果: MainActivity 选项菜单 选项菜单的子菜单 上下文菜单(按住按钮或者EditText弹出) 注意:上下文菜单如何弹出?在注册该菜 ...

  7. android菜单的类型有几种,Android中的Menu(菜单)的三种类型菜单的学习

    今天学习一下菜单组件,在Android中的菜单中有三种①:OptionMenu(选项菜单)②:ContextMenu(上下文菜单) ③:SubMenu(子菜单) 下面分别来学一下 一:OptionMe ...

  8. MFC-5动态更新窗体菜单1

    #include <afxwin.h>//必须加载此文件,该文件中定义了所有MFC相关的类 #include "resource.h"class MyFrame:pub ...

  9. android动态更新配置文件,Android如何动态修改Manifest文件

    修改manifest文件Android Manifest.xml,添加相应的声明.在这里,我们需要将新定义的活动PrefsActivity注册到manifest文件. 同前面一样,在Eclipse中打 ...

最新文章

  1. C语言 数组传递与值传递讲解
  2. JAVA的内省机制(introspector)与反射机制(reflection)
  3. C++ 静态成员函数
  4. amazon alexa_亚马逊使向自定义Alexa Skills添加声音变得更加容易
  5. 删除 字符串中‘*’号 两端的除外。指针h、p分别指向第一个和最后一个字符
  6. (78)Verilog HDL条件编译:`ifdef
  7. 如何进入ThinkSystem系列服务器SAS RAID阵列配置界面
  8. vdbench的作用_Vdbench----文件系统IO,一致性校验,常见问题
  9. js如何获取当前页面url网址信息
  10. openstack RPM打包
  11. 中国邮政国际航空挂号信是可以网上查询跟踪的
  12. 基于莱维飞行和随机游动策略的灰狼算法-附代码
  13. 微信 小程序 python 商城_微信小程序——商城篇
  14. Flink 累加器Accumulator
  15. 电脑是否存在内存泄漏_如何避免内存泄露
  16. python有道字典_有道词典python版
  17. python调用大漠找图_按键精灵大漠插件找图使用方法
  18. 多媒体技术基本概念汇总
  19. 国外主机搭php访问慢_针对海外云服务器访问速度慢的解决方案
  20. 利用多线程爬虫搭建代理ip池的两种方法(含源码)

热门文章

  1. 爆肝万字,终于搞定这篇⛵神经网络搭建全全全流程!学不会你来找我~
  2. CVPR2018 目标检测(object detection)算法总览
  3. 批量去除PDF水印 —— quicker 键鼠模拟操作
  4. CloudCompare 插件调试
  5. 12本互联网科技大佬推荐的必读书籍
  6. CAN总线设计---CAN节点的电容、CAN终端电阻、CAN总线共模电感/共模扼流圈
  7. Centos 7安装步骤
  8. Nginx负载均衡自带健康检测详解
  9. 航空模型手工制作_一次性筷子飞机模型手工制作过程
  10. php自动生成发票,PHP创建PDF发票