menu_menuconfig - CSDN
  • 【Android】Menu详解

    2017-04-29 15:14:01
    要提供熟悉而一致的用户体验,您应使用 Menu API 呈现 Activity 中的用户操作和其他选项。从 Android 3.0(API 级别 11)开始,采用 Android 技术的设备不必再提供一个专用“菜单”按钮。随着这种改变,Android 应用...

    菜单是许多应用类型中常见的用户界面组件。要提供熟悉而一致的用户体验,您应使用 Menu API 呈现 Activity 中的用户操作和其他选项。

    从 Android 3.0(API 级别 11)开始,采用 Android 技术的设备不必再提供一个专用“菜单”按钮。随着这种改变,Android 应用需摆脱对包含 6 个项目的传统菜单面板的依赖,取而代之的是要提供一个应用栏来呈现常见的用户操作。

    尽管某些菜单项的设计和用户体验已发生改变,但定义一系列操作和选项所使用的语义仍是以 Menu API 为基础。本指南将介绍所有 Android 版本系统中三种基本菜单或操作呈现效果的创建方法:

    1. 选项菜单和应用栏

      选项菜单是某个 Activity 的主菜单项, 供您放置对应用产生全局影响的操作,如“搜索”、“撰写电子邮件”和“设置”。

      请参阅创建选项菜单部分。

    2. 上下文菜单和上下文操作模式

      上下文菜单是用户长按某一元素时出现的浮动菜单。 它提供的操作将影响所选内容或上下文框架。

      上下文操作模式在屏幕顶部栏显示影响所选内容的操作项目,并允许用户选择多项。

      请参阅创建上下文菜单部分。

    3. 弹出菜单

      弹出菜单将以垂直列表形式显示一系列项目,这些项目将锚定到调用该菜单的视图中。 它特别适用于提供与特定内容相关的大量操作,或者为命令的另一部分提供选项。 弹出菜单中的操作不会直接影响对应的内容,而上下文操作则会影响。 相反,弹出菜单适用于与您 Activity 中的内容区域相关的扩展操作。

      请参阅创建弹出菜单部分。

    使用 XML 定义菜单

    对于所有菜单类型,Android 提供了标准的 XML 格式来定义菜单项。您应在 XML 菜单资源中定义菜单及其所有项,而不是在 Activity 的代码中构建菜单。定义后,您可以在 Activity 或片段中扩充菜单资源(将其作为 Menu 对象加载)。

    使用菜单资源是一种很好的做法,原因如下:

    • 更易于使用 XML 可视化菜单结构
    • 将菜单内容与应用的行为代码分离
    • 允许您利用应用资源框架,为不同的平台版本、屏幕尺寸和其他配置创建备用菜单配置

    要定义菜单,请在项目 res/menu/ 目录内创建一个 XML 文件,并使用以下元素构建菜单:

    1. 定义 Menu,即菜单项的容器。

    2. 创建 MenuItem,此元素表示菜单中的一项,可能包含嵌套的

    3. 元素的不可见容器(可选)。它支持您对菜单项进行分类,使其共享活动状态和可见性等属性。 如需了解详细信息,请参阅创建菜单组部分。

    以下是名为 game_menu.xml 的菜单示例:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/new_game"
              android:icon="@drawable/ic_new_game"
              android:title="@string/new_game"
              android:showAsAction="ifRoom"/>
        <item android:id="@+id/help"
              android:icon="@drawable/ic_help"
              android:title="@string/help" />
    </menu>

    元素支持多个属性,您可使用这些属性定义项目的外观和行为。上述菜单中的项目包括以下属性:

    1. android:id
      项目特有的资源 ID,让应用能够在用户选择项目时识别该项目。
    2. android:icon
      引用一个要用作项目图标的可绘制对象。
    3. android:title
      引用一个要用作项目标题的字符串。
    4. android:showAsAction
      指定此项应作为操作项目显示在应用栏中的时间和方式。

    这些是您应使用的最重要属性,但还有许多其他属性。有关所有受支持属性的信息,请参阅菜单资源文档。

    您可以通过以 子元素的形式添加

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/file"
              android:title="@string/file" >
            <!-- "file" submenu -->
            <menu>
                <item android:id="@+id/create_new"
                      android:title="@string/create_new" />
                <item android:id="@+id/open"
                      android:title="@string/open" />
            </menu>
        </item>
    </menu>

    要在 Activity 中使用菜单,您需要使用 MenuInflater.inflate() 扩充菜单资源(将 XML 资源转换为可编程对象)。在下文中,您将了解如何扩充每种类型的菜单。

    创建选项菜单

    在选项菜单中,您应当包括与当前 Activity 上下文相关的操作和其他选项,如“搜索”、“撰写电子邮件”和“设置”。

    选项菜单中的项目在屏幕上的显示位置取决于您开发的应用所适用的 Android 版本:

    • 如果您开发的应用适用于 Android 2.3.x(API 级别 10)或更低版本,则当用户按“菜单”按钮时,选项菜单的内容会出现在屏幕底部,如图 所示。打开时,第一个可见部分是图标菜单,其中包含多达 6 个菜单项。 如果菜单包括 6 个以上项目,则 Android 会将第六项和其余项目放入溢出菜单。用户可以通过选择“更多”打开该菜单。

      options_menu

    • 如果您开发的应用适用于 Android 3.0(API 级别 11)及更高版本,则选项菜单中的项目将出现在应用栏中。 默认情况下,系统会将所有项目均放入操作溢出菜单中。用户可以使用应用栏右侧的操作溢出菜单图标(或者,通过按设备“菜单”按钮(如有))显示操作溢出菜单。 要支持快速访问重要操作,您可以将 android:showAsAction=”ifRoom” 添加到对应的 元素,从而将几个项目提升到应用栏中(请参阅图 2)。

      actionbar

    如需了解有关操作项目和其他应用栏行为的详细信息,请参阅添加应用栏培训课程。

    您可以通过 Activity 子类或 Fragment 子类为选项菜单声明项目。如果您的 Activity 和片段均为选项菜单声明项目,则这些项目将合并到 UI 中。 系统将首先显示 Activity 的项目,随后按每个片段添加到 Activity 中的顺序显示各片段的项目。 如有必要,您可以使用 android:orderInCategory 属性,对需要移动的每个 中的菜单项重新排序。

    要为 Activity 指定选项菜单,请重写 onCreateOptionsMenu()(片段会提供自己的 onCreateOptionsMenu() 回调)。通过此方法,您可以将菜单资源(使用 XML 定义)扩充到回调中提供的 Menu 中。 例如:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.game_menu, menu);
        return true;
    }

    此外,您还可以使用 add() 添加菜单项,并使用 findItem() 检索项目,以便使用 MenuItem API 修改其属性。

    如果您开发的应用适用于 Android 2.3.x 及更低版本,则当用户首次打开选项菜单时,系统会调用 onCreateOptionsMenu() 来创建该菜单。 如果您开发的应用适用于 Android 3.0 及更高版本,则系统将在启动 Activity 时调用 onCreateOptionsMenu(),以便向应用栏显示项目。

    处理点击事件

    用户从选项菜单中选择项目(包括应用栏中的操作项目)时,系统将调用 Activity 的 onOptionsItemSelected() 方法。 此方法将传递所选的 MenuItem。您可以通过调用 getItemId() 方法来识别项目,该方法将返回菜单项的唯一 ID(由菜单资源中的 android:id 属性定义,或通过提供给 add() 方法的整型数定义)。 您可以将此 ID 与已知的菜单项匹配,以执行适当的操作。例如:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
            case R.id.new_game:
                newGame();
                return true;
            case R.id.help:
                showHelp();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    成功处理菜单项后,系统将返回 true。如果未处理菜单项,则应调用 onOptionsItemSelected() 的超类实现(默认实现将返回 false)。

    如果 Activity 包括片段,则系统将依次为 Activity 和每个片段(按照每个片段的添加顺序)调用 onOptionsItemSelected(),直到有一个返回结果为 true 或所有片段均调用完毕为止。

    提示:Android 3.0 新增了一项功能,支持您在 XML 中使用 android:onClick 属性为菜单项定义点击行为。该属性的值必须是 Activity 使用菜单定义的方法的名称。 该方法必须是公用的,且接受单个 MenuItem 参数;当系统调用此方法时,它会传递所选的菜单项。如需了解详细信息和示例,请参阅菜单资源文档。

    提示:如果应用包含多个 Activity,且其中某些 Activity 提供相同的选项菜单,则可考虑创建一个仅实现 onCreateOptionsMenu() 和 onOptionsItemSelected() 方法的 Activity。然后,为每个应共享相同选项菜单的 Activity 扩展此类。 通过这种方式,您可以管理一个用于处理菜单操作的代码集,且每个子级类均会继承菜单行为。若要将菜单项添加到一个子级 Activity,请重写该 Activity 中的 onCreateOptionsMenu()。 调用 super.onCreateOptionsMenu(menu),以便创建原始菜单项,然后使用 menu.add() 添加新菜单项。 此外,您还可以替代各个菜单项的超类行为。

    在运行时更改菜单项

    系统调用 onCreateOptionsMenu() 后,将保留您填充的 Menu 实例。除非菜单由于某些原因而失效,否则不会再次调用 onCreateOptionsMenu()。但是,您仅应使用 onCreateOptionsMenu() 来创建初始菜单状态,而不应使用它在 Activity 生命周期中执行任何更改。

    如需根据在 Activity 生命周期中发生的事件修改选项菜单,则可通过 onPrepareOptionsMenu() 方法执行此操作。此方法向您传递 Menu 对象(因为该对象目前存在),以便您能够对其进行修改,如添加、移除或禁用项目。(此外,片段还提供 onPrepareOptionsMenu() 回调。)

    在 Android 2.3.x 及更低版本中,每当用户打开选项菜单时(按“菜单”按钮),系统均会调用 onPrepareOptionsMenu()。

    在 Android 3.0 及更高版本中,当菜单项显示在应用栏中时,选项菜单被视为始终处于打开状态。 发生事件时,如果您要执行菜单更新,则必须调用 invalidateOptionsMenu() 来请求系统调用 onPrepareOptionsMenu()。

    :切勿根据目前处于焦点的 View 更改选项菜单中的项目。 处于触摸模式(用户未使用轨迹球或方向键)时,视图无法形成焦点,因此切勿根据焦点修改选项菜单中的项目。 若要为 View 提供上下文相关的菜单项,请使用上下文菜单。

    创建上下文菜单

    上下文菜单提供了许多操作,这些操作影响 UI 中的特定项目或上下文框架。您可以为任何视图提供上下文菜单,但这些菜单通常用于 ListView、GridView 或用户可直接操作每个项目的其他视图集合中的项目。
    menu-context

    提供上下文操作的方法有两种:

    • 使用浮动上下文菜单。用户长按(按住)一个声明支持上下文菜单的视图时,菜单显示为菜单项的浮动列表(类似于对话框)。 用户一次可对一个项目执行上下文操作。

    • 使用上下文操作模式。此模式是 ActionMode 的系统实现,它将在屏幕顶部显示上下文操作栏,其中包括影响所选项的操作项目。当此模式处于活动状态时,用户可以同时对多项执行操作(如果应用允许)。

      :上下文操作模式可用于 Android 3.0(API 级别 11)及更高版本,是显示上下文操作(如果可用)的首选方法。如果应用支持低于 3.0 版本的系统,则应在这些设备上回退到浮动上下文菜单。

    创建浮动上下文菜单

    要提供浮动上下文菜单,请执行以下操作:

    1. 通过调用 registerForContextMenu(),注册应与上下文菜单关联的 View 并将其传递给 View。
      如果 Activity 使用 ListView 或 GridView 且您希望每个项目均提供相同的上下文菜单,请通过将 ListView 或 GridView 传递给 registerForContextMenu(),为上下文菜单注册所有项目。

    2. 在 Activity 或 Fragment 中实现 onCreateContextMenu() 方法。
      当注册后的视图收到长按事件时,系统将调用您的 onCreateContextMenu() 方法。在此方法中,您通常可通过扩充菜单资源来定义菜单项。例如:

      @Override
      public void onCreateContextMenu(ContextMenu menu, View v,
                                  ContextMenuInfo menuInfo) {
      super.onCreateContextMenu(menu, v, menuInfo);
      MenuInflater inflater = getMenuInflater();
      inflater.inflate(R.menu.context_menu, menu);
      }

      MenuInflater 允许您通过菜单资源扩充上下文菜单。回调方法参数包括用户所选的 View,以及一个提供有关所选项的附加信息的 ContextMenu.ContextMenuInfo 对象。如果 Activity 有多个视图,每个视图均提供不同的上下文菜单,则可使用这些参数确定要扩充的上下文菜单。

    3. 实现 onContextItemSelected()。
      用户选择菜单项时,系统将调用此方法,以便您能够执行适当的操作。 例如:

      @Override
      public boolean onContextItemSelected(MenuItem item) {
          AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
          switch (item.getItemId()) {
              case R.id.edit:
                  editNote(info.id);
                  return true;
              case R.id.delete:
                  deleteNote(info.id);
                  return true;
              default:
                  return super.onContextItemSelected(item);
          }
      }

      getItemId() 方法将查询所选菜单项的 ID,您应使用 android:id 属性将此 ID 分配给 XML 中的每个菜单项,如使用 XML 定义菜单部分所示。

      成功处理菜单项后,系统将返回 true。如果未处理菜单项,则应将菜单项传递给超类实现。 如果 Activity 包括片段,则 Activity 将先收到此回调。 通过在未处理的情况下调用超类,系统会将事件逐一传递给每个片段中相应的回调方法(按照每个片段的添加顺序),直到返回 true 或 false 为止。(Activity 和 android.app.Fragment 的默认实现返回 false,因此您始终应在未处理的情况下调用超类。)

    使用上下文操作模式

    上下文操作模式是 ActionMode 的一种系统实现,它将用户交互的重点转到执行上下文操作上。用户通过选择项目启用此模式时,屏幕顶部将出现一个“上下文操作栏”,显示用户可对当前所选项执行的操作。 启用此模式后,用户可以选择多个项目(若您允许)、取消选择项目以及继续在 Activity 内导航(在您允许的最大范围内)。 当用户取消选择所有项目、按“返回”按钮或选择操作栏左侧的“完成”操作时,该操作模式将会停用,且上下文操作栏将会消失。

    :上下文操作栏不一定与应用栏相关联。 尽管表面上看来上下文操作栏取代了应用栏的位置,但事实上二者独立运行。

    对于提供上下文操作的视图,当出现以下两个事件(或之一)时,您通常应调用上下文操作模式:

    • 用户长按视图。
    • 用户选中复选框或视图内的类似 UI 组件。

    应用如何调用上下文操作模式以及如何定义每个操作的行为,具体取决于您的设计。 设计基本上分为两种:

    • 针对单个任意视图的上下文操作。
    • 针对 ListView 或 GridView 中项目组的批处理上下文操作(允许用户选择多个项目并针对所有项目执行操作)。

    下文介绍每种场景所需的设置。

    为单个视图启用上下文操作模式

    如果希望仅当用户选择特定视图时才调用上下文操作模式,则应:

    1. 实现 ActionMode.Callback 接口。在其回调方法中,您既可以为上下文操作栏指定操作,又可以响应操作项目的点击事件,还可以处理操作模式的其他生命周期事件。
    2. 当需要显示操作栏时(例如,用户长按视图),请调用 startActionMode()。

    例如:

    1. 实现 ActionMode.Callback 接口:

      private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
      
      // Called when the action mode is created; startActionMode() was called
      @Override
      public boolean onCreateActionMode(ActionMode mode, Menu menu) {
          // Inflate a menu resource providing context menu items
          MenuInflater inflater = mode.getMenuInflater();
          inflater.inflate(R.menu.context_menu, menu);
          return true;
      }
      
      // Called each time the action mode is shown. Always called after onCreateActionMode, but
      // may be called multiple times if the mode is invalidated.
      @Override
      public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
          return false; // Return false if nothing is done
      }
      
      // Called when the user selects a contextual menu item
      @Override
      public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
          switch (item.getItemId()) {
              case R.id.menu_share:
                  shareCurrentItem();
                  mode.finish(); // Action picked, so close the CAB
                  return true;
              default:
                  return false;
          }
      }
      
      // Called when the user exits the action mode
      @Override
      public void onDestroyActionMode(ActionMode mode) {
          mActionMode = null;
          }
      };

      请注意,这些事件回调与选项菜单的回调几乎完全相同,只是其中每个回调还会传递与事件相关联的 ActionMode 对象。您可以使用 ActionMode API 对 CAB 进行各种更改,例如:使用 setTitle() 和 setSubtitle()(这对指示要选择多少个项目非常有用)修改标题和副标题。
      另请注意,操作模式被销毁时,上述示例会将 mActionMode 变量设置为 null。 在下一步中,您将了解如何初始化该变量,以及保存 Activity 或片段中的成员变量有何作用。

    2. 调用 startActionMode() 以便适时启用上下文操作模式,例如:响应对 View 的长按操作:

      someView.setOnLongClickListener(new View.OnLongClickListener() {
          // Called when the user long-clicks on someView
          public boolean onLongClick(View view) {
              if (mActionMode != null) {
                  return false;
              }
      
              // Start the CAB using the ActionMode.Callback defined above
              mActionMode = getActivity().startActionMode(mActionModeCallback);
              view.setSelected(true);
              return true;
          }
      });

      当您调用 startActionMode() 时,系统将返回已创建的 ActionMode。通过将其保存在成员变量中,您可以更改上下文操作栏来响应其他事件。 在上述示例中, ActionMode 用于在启动操作模式之前检查成员是否为空,以确保当 ActionMode 实例已激活时不再重建该实例。

    在 ListView 或 GridView 中启用批处理上下文操作

    如果您在 ListView 或 GridView 中有一组项目(或 AbsListView 的其他扩展),且需要允许用户执行批处理操作,则应:

    • 实现 AbsListView.MultiChoiceModeListener 接口,并使用 setMultiChoiceModeListener() 为视图组设置该接口。在侦听器的回调方法中,您既可以为上下文操作栏指定操作,也可以响应操作项目的点击事件,还可以处理从 ActionMode.Callback 接口继承的其他回调。
    • 使用 CHOICE_MODE_MULTIPLE_MODAL 参数调用 setChoiceMode()。
      例如:

      ListView listView = getListView();
      listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
      listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
      
          @Override
          public void onItemCheckedStateChanged(ActionMode mode, int position,
                                                long id, boolean checked) {
              // Here you can do something when items are selected/de-selected,
              // such as update the title in the CAB
          }
      
          @Override
          public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
              // Respond to clicks on the actions in the CAB
              switch (item.getItemId()) {
                  case R.id.menu_delete:
                      deleteSelectedItems();
                      mode.finish(); // Action picked, so close the CAB
                      return true;
                  default:
                      return false;
              }
          }
      
          @Override
          public boolean onCreateActionMode(ActionMode mode, Menu menu) {
              // Inflate the menu for the CAB
              MenuInflater inflater = mode.getMenuInflater();
              inflater.inflate(R.menu.context, menu);
              return true;
          }
      
          @Override
          public void onDestroyActionMode(ActionMode mode) {
              // Here you can make any necessary updates to the activity when
              // the CAB is removed. By default, selected items are deselected/unchecked.
          }
      
          @Override
          public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
              // Here you can perform updates to the CAB due to
              // an invalidate() request
              return false;
          }
      });

      就这么简单。现在,当用户通过长按选择项目时,系统即会调用 onCreateActionMode() 方法,并显示包含指定操作的上下文操作栏。当上下文操作栏可见时,用户可以选择其他项目。

      在某些情况下,如果上下文操作提供常用的操作项目,则您可能需要添加一个复选框或类似的 UI 元素来支持用户选择项目,这是因为他们可能没有发现长按行为。用户选中该复选框时,您可以通过使用 setItemChecked() 将相应的列表项设置为选中状态,以此调用上下文操作模式。

    创建弹出菜单

    popupmenu

    PopupMenu 是锚定到 View 的模态菜单。如果空间足够,它将显示在定位视图下方,否则显示在其上方。它适用于:

    • 为与特定内容确切相关的操作提供溢出样式菜单(例如,Gmail 的电子邮件标头,如图 4 所示)。

      :这与上下文菜单不同,后者通常用于影响所选内容的操作。 对于影响所选内容的操作,请使用上下文操作模式或浮动上下文菜单。

    • 提供命令语句的另一部分(例如,标记为“添加”且使用不同的“添加”选项生成弹出菜单的按钮)。

    • 提供类似于 Spinner 且不保留永久选择的下拉菜单。

      :PopupMenu 在 API 级别 11 及更高版本中可用。


    如果使用 XML 定义菜单,则显示弹出菜单的方法如下:
    1. 实例化 PopupMenu 及其构造函数,该函数将提取当前应用的 Context 以及菜单应锚定到的 View。
    2. 使用 MenuInflater 将菜单资源扩充到 PopupMenu.getMenu() 返回的 Menu 对象中。
    3. 调用 PopupMenu.show()。
      例如,以下是一个使用 android:onClick 属性显示弹出菜单的按钮:
    <ImageButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_overflow_holo_dark"
        android:contentDescription="@string/descr_overflow_button"
        android:onClick="showPopup" />
    稍后,Activity 可按照如下方式显示弹出菜单:
    public void showPopup(View v) {
        PopupMenu popup = new PopupMenu(this, v);
        MenuInflater inflater = popup.getMenuInflater();
        inflater.inflate(R.menu.actions, popup.getMenu());
        popup.show();
    }
    在 API 级别 14 及更高版本中,您可以将两行合并在一起,使用 PopupMenu.inflate() 扩充菜单。 当用户选择项目或触摸菜单以外的区域时,系统即会清除此菜单。 您可使用 PopupMenu.OnDismissListener 侦听清除事件。

    处理点击事件

    要在用户选择菜单项时执行操作,您必须实现 PopupMenu.OnMenuItemClickListener 接口,并通过调用 setOnMenuItemclickListener() 将其注册到 PopupMenu。 用户选择项目时,系统会在接口中调用 onMenuItemClick() 回调。 例如:
    public void showMenu(View v) {
        PopupMenu popup = new PopupMenu(this, v);
    
        // This activity implements OnMenuItemClickListener
        popup.setOnMenuItemClickListener(this);
        popup.inflate(R.menu.actions);
        popup.show();
    }
    
    @Override
    public boolean onMenuItemClick(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.archive:
                archive(item);
                return true;
            case R.id.delete:
                delete(item);
                return true;
            default:
                return false;
        }
    }
    

    创建菜单组

    菜单组是指一系列具有某些共同特征的菜单项。通过菜单组,您可以:
    • 使用 setGroupVisible() 显示或隐藏所有项目
    • 使用 setGroupEnabled() 启用或禁用所有项目
    • 使用 setGroupCheckable() 指定所有项目是否可选中
      通过将 元素嵌套在菜单资源中的 元素内,或者通过使用 add() 方法指定组 ID,您可以创建组。

    以下是包含组的菜单资源示例:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/menu_save"
              android:icon="@drawable/menu_save"
              android:title="@string/menu_save" />
        <!-- menu group -->
        <group android:id="@+id/group_delete">
            <item android:id="@+id/menu_archive"
                  android:title="@string/menu_archive" />
            <item android:id="@+id/menu_delete"
                  android:title="@string/menu_delete" />
        </group>
    </menu>

    组中的项目出现在与第一项相同的级别,即:菜单中的所有三项均为同级。 但是,您可以通过引用组 ID 并使用上面列出的方法,修改组中两项的特征。此外,系统也绝不会分离已分组的项目。 例如,如果为每个项目声明 android:showAsAction=”ifRoom”,则它们会同时显示在操作栏或操作溢出菜单中。

    使用可选中的菜单项

    作为启用/禁用选项的接口,菜单非常实用,既可针对独立选项使用复选框,也可针对互斥选项组使用单选按钮。 图 5 显示了一个子菜单,其中的项目可使用单选按钮选中。

    :“图标菜单”(在选项菜单中)的菜单项无法显示复选框或单选按钮。 如果您选择使“图标菜单”中的项目可选中,则必须在选中状态每次发生变化时交换图标和/或文本,手动指出该状态。

    您可以使用 元素中的 android:checkable 属性为各个菜单项定义可选中的行为,或者使用 元素中的 android:checkableBehavior 属性为整个组定义可选中的行为。例如,此菜单组中的所有项目均可使用单选按钮选中:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <group android:checkableBehavior="single">
            <item android:id="@+id/red"
                  android:title="@string/red" />
            <item android:id="@+id/blue"
                  android:title="@string/blue" />
        </group>
    </menu>

    android:checkableBehavior 属性接受以下任一选项:

    1. single

      组中只有一个项目可以选中(单选按钮)

    2. all

      所有项目均可选中(复选框)

    3. none

      所有项目均无法选中

    您可以使用 元素中的 android:checked 属性将默认的选中状态应用于项目,并可使用 setChecked() 方法在代码中更改此默认状态。

    选择可选中项目后,系统将调用所选项目的相应回调方法(例如,onOptionsItemSelected())。 此时,您必须设置复选框的状态,因为复选框或单选按钮不会自动更改其状态。 您可以使用 isChecked() 查询项目的当前状态(正如用户选择该项目之前一样),然后使用 setChecked() 设置选中状态。例如:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.vibrate:
            case R.id.dont_vibrate:
                if (item.isChecked()) item.setChecked(false);
                else item.setChecked(true);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    如果未通过这种方式设置选中状态,则项目的可见状态(复选框或单选按钮)不会因为用户选择它而发生变化。 如果已设置该状态,则 Activity 会保留项目的选中状态。这样一来,当用户稍后打开菜单时,您设置的选中状态将会可见。

    :可选中菜单项的使用往往因会话而异,且在应用销毁后不予保存。 如果您想为用户保存某些应用设置,则应使用共享首选项存储数据。

    添加基于 Intent 的菜单项

    有时,您希望菜单项通过使用 Intent 启动 Activity(无论该 Activity 是位于您的应用还是其他应用中)。如果您知道自己要使用的 Intent,且具有启动 Intent 的特定菜单项,则可在相应的 on-item-selected 回调方法(例如,onOptionsItemSelected() 回调)期间使用 startActivity() 执行 Intent。

    但是,如果不确定用户的设备是否包含可处理 Intent 的应用,则添加调用 Intent 的菜单项可能会导致该菜单项无法正常工作,这是因为 Intent 可能无法解析为 Activity。 为了解决这一问题,当 Android 在设备上找到可处理 Intent 的 Activity 时,则允许您向菜单动态添加菜单项。

    要根据接受 Intent 的可用 Activity 添加菜单项,请执行以下操作:

    1. 使用类别 CATEGORY_ALTERNATIVE 和/或 CATEGORY_SELECTED_ALTERNATIVE 以及任何其他要求定义 Intent。
    2. 调用 Menu.addIntentOptions()。Android 随后即会搜索能够执行 Intent 的所有应用,并将其添加到菜单中。

    如果未安装可处理 Intent 的应用,则不会添加任何菜单项。

    : CATEGORY_SELECTED_ALTERNATIVE 用于处理屏幕上当前所选的元素。因此,只有在 onCreateContextMenu() 中创建菜单时,才能使用它。

    例如:

    @Override
    public boolean onCreateOptionsMenu(Menu menu){
        super.onCreateOptionsMenu(menu);
    
        // Create an Intent that describes the requirements to fulfill, to be included
        // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE.
        Intent intent = new Intent(null, dataUri);
        intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
    
        // Search and populate the menu with acceptable offering applications.
        menu.addIntentOptions(
             R.id.intent_group,  // Menu group to which new items will be added
             0,      // Unique item ID (none)
             0,      // Order for the items (none)
             this.getComponentName(),   // The current activity name
             null,   // Specific items to place first (none)
             intent, // Intent created above that describes our requirements
             0,      // Additional flags to control items (none)
             null);  // Array of MenuItems that correlate to specific items (none)
    
        return true;
    }

    如果发现 Activity 提供的 Intent 过滤器与定义的 Intent 匹配,则会添加菜单项,并使用 Intent 过滤器 android:label 中的值作为菜单项标题,使用应用图标作为菜单项图标。addIntentOptions() 方法将返回已添加的菜单项数量。

    :调用 addIntentOptions() 方法时,它将使用第一个参数中指定的菜单组替代所有菜单项。

    允许将 Activity 添加到其他菜单中

    此外,您还可以为其他应用提供您的 Activity 服务,以便您的应用能够包含在其他应用的菜单中(与上述角色相反)。

    要包含在其他应用菜单中,您需要按常规方式定义 Intent 过滤器,但请确保为 Intent 过滤器类别添加 CATEGORY_ALTERNATIVE 和/或 CATEGORY_SELECTED_ALTERNATIVE 值。例如:

    <intent-filter label="@string/resize_image">
        ...
        <category android:name="android.intent.category.ALTERNATIVE" />
        <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
        ...
    </intent-filter>

    请仔细阅读 Intent 和 Intent 过滤器文档中更多有关编写 Intent 过滤器的内容。

    有关使用此方法的应用示例,请参阅记事本示例代码。

    展开全文
  • &lt;LinearLayout xmlns:android="...  android:layout_width="match_parent"  android:layout_height="match_parent"&gt;    &lt;Button ... android:i...

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:layout_width="match_parent"

        android:layout_height="match_parent">

     

        <Button

            android:id="@+id/menu"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="菜单"/>

    </LinearLayout>

     

     

     

    //showAsAction属性值:always直接在标题栏显示

    never:不显示

    with Text:控制图标和文本一起显示

    ifRoom:有空间就显示

     

     

    //icon设置为图片,默认不显示文字

    <?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">

     

        <item android:id="@+id/option_1"

            android:title="设置"

            app:showAsAction="always"/>

        <item android:title="保存"/>

        <item android:title="更多设置">

            <menu>

                <item android:title="紫菜蛋一"/>

                <item android:title="紫菜蛋儿"/>

                <item android:title="子菜单上"/>

            </menu>

        </item>

    </menu>

     

    一:OptionMenu

    public class MainActivity extends AppCompatActivity {

     

        @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_main);

            

            //覆盖onCreateOptionsMenu方法

            //覆盖onOptionsItemSelected方法

        }

     

        @Override

        public boolean onCreateOptionsMenu(Menu menu) {

            getMenuInflater().inflate(R.menu.option,menu);

            return true;

        }

     

        @Override

        public boolean onOptionsItemSelected(MenuItem item) {

            switch (item.getItemId()){

                case R.id.option_1:

                    Toast.makeText(MainActivity.this,"shezhi",Toast.LENGTH_LONG).show();

            }

            return super.onOptionsItemSelected(item);

        }

    }

     

    二:ContextMenu

    public class MainActivity extends AppCompatActivity {

     

        @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_main);

     

    //        1.注册

            registerForContextMenu(findViewById(R.id.menu));

    //        2创建 覆盖onCreateContextMenu

    //        3.菜单项操作 覆盖onContextItemSelected

        }

     

        @Override

        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {

            getMenuInflater().inflate(R.menu.option,menu);

        }

     

        @Override

        public boolean onContextItemSelected(MenuItem item) {

            switch (item.getItemId()){

                case R.id.option_1:

                    Toast.makeText(MainActivity.this,"menu",Toast.LENGTH_LONG).show();

                    break;

            }

            return super.onContextItemSelected(item);

        }

    }

     

     

    第二种效果:

    public class MainActivity extends AppCompatActivity {

     

        @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_main);

     

    //        为按钮设置上下文操作模式

    //        1 实现ActionMode CallBack

    //        2 在view的长按事件中去启动上下文操作模式

            findViewById(R.id.menu).setOnLongClickListener(new View.OnLongClickListener() {

                @Override

                public boolean onLongClick(View view) {

                    startActionMode(cb);

                    return false;

                }

            });

     

        }

     

        ActionMode.Callback cb = new ActionMode.Callback() {

     

    //        创建,在启动上下文操作模式(startActionMode(Callback))时调用

            @Override

            public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {

                getMenuInflater().inflate(R.menu.option,menu);

                return true;

            }

     

    //        在创建方法后进行调用

            @Override

            public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {

                return false;

            }

     

     

            @Override

            public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {

                switch (menuItem.getItemId()){

                    case R.id.option_1:

                        Toast.makeText(MainActivity.this,"menu",Toast.LENGTH_LONG).show();

                }

                return false;

            }

     

    //        上下文操作模式结束时被调用

            @Override

            public void onDestroyActionMode(ActionMode actionMode) {

     

            }

        };

    }

     

    三:PopupMenu

     

     

    public class MainActivity extends AppCompatActivity {

     

        @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_main);

     

            final Button button = (Button)findViewById(R.id.menu);

    //        演示popuMenu

            button.setOnClickListener(new View.OnClickListener() {

                @Override

                public void onClick(View view) {

    //                1 实例化popuMenu对象(参数2:被锚定的view)

                    PopupMenu menu = new PopupMenu(MainActivity.this,button);

    //                2 加载菜单资源:利用Menuinflater将Menu资源加载到PopupMenu.getMenu()所返回的Menu对象中

    //                将R.menu.xx对应的菜单资源加载到弹出式菜单中

                    menu.getMenuInflater().inflate(R.menu.option,menu.getMenu());

    //                3 为popupMenu设置点击监听器

                    menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {

                        @Override

                        public boolean onMenuItemClick(MenuItem menuItem) {

                            switch (menuItem.getItemId()){

                                case R.id.option_1:

                                    Toast.makeText(MainActivity.this,"menu",Toast.LENGTH_LONG).show();

                            }

                            return false;

                        }

                    });

    //                4千万不要忘记这一步

                    menu.show();

                }

            });

        }

     

     

    }

    展开全文
  • 一、 使用xml定义Menu 菜单资源文件必须放在res/menu目录中。菜单资源文件必须使用标签作为根节点。除了标签外,还有另外两个标签用于设置菜单项和分组,这两个标签是和。 标签没有任何属性,但可以嵌套在标签中,...

    一、 使用xml定义Menu

    菜单资源文件必须放在res/menu目录中。菜单资源文件必须使用<menu>标签作为根节点。除了<menu>标签外,还有另外两个标签用于设置菜单项和分组,这两个标签是<item>和<group>。

    <menu>标签没有任何属性,但可以嵌套在<item>标签中,表示子菜单的形式。不过<item>标签中不能再嵌入<item>标签。

    1.<item>标签的属性含义如下:

    Id:表示菜单项的资源ID

    menuCategory:同种菜单项的种类。该属性可取4个值:container、system、secondary和alternative。通过menuCategroy属性可以控制菜单项的位置。例如将属性设为system,表示该菜单项是系统菜单,应放在其他种类菜单项的后面。

    orderInCategor:同种类菜单的排列顺序。该属性需要设置一个整数值。例如menuCategory属性值都为system的3个菜单项(item1、item2和item3)。将这3个菜单项的orderInCategory属性值设为3、2、1,那么item3会显示在最前面,而item1会显示在最后面。

    title:菜单项标题(菜单项显示的文本)

    titleCondensed:菜单项的短标题。当菜单项标题太长时会显示该属性值

    icon:菜单项图标资源ID

    alphabeticShortcut:菜单项的字母快捷键

    numericShortcut:菜单项的数字快捷键

    checkable:表示菜单项是否带复选框。该属性可设计为true或false

    checked:如果菜单项带复选框(checkable属性为true),该属性表示复选框默认状态是否被选中。可设置的值为true或false

    visible:菜单项默认状态是否可视

    enable:菜单项默认状态是否被激活

    2.<group>标签的属性含义如下:

    id:表示菜单组的ID

    menuCategory:与<item>标签的同名属性含义相同。只是作用域为菜单组

    orderInCategory:与<item>标签的同名属性含义相同。只是作用域为菜单组

    checkableBehavior:设置该组所有菜单项上显示的选择组件(CheckBox或Radio Button)。如果将该属性值设为all,显示CheckBox组件;如果设为single,显示Radio Button组件;如果设为none,显示正常的菜单项(不显示任何选择组件)。要注意的是,Android SDK官方文档在解释该属性时有一个笔误,原文是:

    Whether the items are checkable. Valid values: none, all(exclusive/radiobuttons), single(non-exclusive/checkboxes).

    相反了,正确应该是

    all(non-exclusive/checkboxes),single(exclusive/radiobuttons).

    visible:表示当前组中所有菜单项是否显示。该属性可设置的值是true或false

    enable:表示当前组中所有菜单项是否被激活。该属性可设置的值是true或false

    3.具体使用

    在代码中使用

    public boolenonCreateOptionsMenu(Menu menu){

    MenuInflatemenuInflate = getMenuInflate();

    menuInflate.inflate(R.menu.option_menu,menu);

    returntrue;

    }

    二、使用代码定义Menu

    public boolean onCreateOptionsMenu(Menu menu){  

    // 方法一,用代码构建   

     menu.add(Menu.NONE, Menu.NONE, 1, "菜单1");  

     menu.add(Menu.NONE, Menu.NONE, 2, "菜单2");  

     menu.add(Menu.NONE, Menu.NONE, 3, "菜单3");  

     menu.add(Menu.NONE, Menu.NONE, 4, "菜单4");  

    menu.add(Menu.NONE, Menu.NONE, 5, "菜单5");  

    menu.add(Menu.NONE, Menu.NONE, 6, "菜单6");  

    return true;  

    }  

    三、菜单响应

    重写onOptionsItemSelected(MenuItem item)这个方法就可以做响应的操作了。

    四、实例

    res/menu下的activity_main.xml文件

    <menu xmlns:android="http://schemas.android.com/apk/res/android" >
    
        <item
            android:id="@+id/menu_settings"
            android:orderInCategory="1"
            android:icon="@drawable/home"
            android:title="@string/menu_settings"/>
        <item
            android:id="@+id/menu_about"
            android:orderInCategory="2"
            android:icon="@drawable/mine"
            android:title="@string/menu_about"/>
        <item
            android:id="@+id/menu_quit"
            android:orderInCategory="3"
            android:icon="@drawable/more"
            android:title="@string/menu_quit"/>
        
    </menu>

    MainActivity.java文件

    package com.example.menutest;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    	}
    
    	@Override
    	public boolean onCreateOptionsMenu(Menu menu) {
    		// Inflate the menu; this adds items to the action bar if it is present.
    		getMenuInflater().inflate(R.menu.activity_main, menu);
    		return true;
    	}
    
    	@Override
    	public boolean onOptionsItemSelected(MenuItem item) {
    		// TODO Auto-generated method stub
    		switch(item.getItemId()){
    	       case R.id.menu_about:	       
    	           Toast.makeText(MainActivity.this, ""+"关于", Toast.LENGTH_SHORT).show();
    	           break;
    	       case R.id.menu_settings:
    	           
    	           Toast.makeText(MainActivity.this, ""+"设置", Toast.LENGTH_SHORT).show();
    	           break;
    	       case R.id.menu_quit:
    	           
    	           Toast.makeText(MainActivity.this, ""+"退出", Toast.LENGTH_SHORT).show();
    	           break;
    	       default:
    	    	   break;
    	       }
    //	       Toast.makeText(MainActivity.this, ""+item.getItemId(), Toast.LENGTH_SHORT).show();
    	
    		return super.onOptionsItemSelected(item);
    	}
    
    }
    

    运行结果:


    附:自定义菜单的背景参见:http://blog.csdn.net/sodino/article/details/6165132


    展开全文
  • fps=1说明:本文只介绍Android3.0及以上的Menu知识点。菜单的分类菜单是Android应用中非常重要且常见的组成部分,主要可以分为三类:选项菜单、上下文菜单/上下文操作模式以及弹出菜单。它们的主要区别如下:选项...

    转载链接:https://blog.csdn.net/CodingEnding/article/details/78609902?locationNum=9&fps=1

    说明:本文只介绍Android3.0及以上的Menu知识点。

    菜单的分类

    菜单是Android应用中非常重要且常见的组成部分,主要可以分为三类:选项菜单、上下文菜单/上下文操作模式以及弹出菜单。它们的主要区别如下:

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

    • 上下文菜单是用户长按某一元素时出现的浮动菜单。它提供的操作将影响所选内容,主要应用于列表中的每一项元素(如长按列表项弹出删除对话框)。上下文操作模式将在屏幕顶部栏(菜单栏)显示影响所选内容的操作选项,并允许用户选择多项,一般用于对列表类型的数据进行批量操作。

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

    使用XML定义Menu

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

    • 使用XML可以获得更清晰的菜单结构
    • 将菜单内容与应用的逻辑代码分离
    • 可以使用应用资源框架,为不同的平台版本、屏幕尺寸创建最合适的菜单(如对drawable、string等系统资源的使用)

    要定义Menu,我们首先需要在res文件夹下新建menu文件夹,它将用于存储与Menu相关的所有XML文件。

    我们可以使用<menu><item><group>三种XML元素定义Menu,下面简单介绍一下它们:

    • <menu>是菜单项的容器。<menu>元素必须是该文件的根节点,并且能够包含一个或多个<item><group>元素。
    • <item>是菜单项,用于定义MenuItem,可以嵌套<menu>元素,以便创建子菜单。
    • <group><item>元素的不可见容器(可选)。可以使用它对菜单项进行分组,使一组菜单项共享可用性和可见性等属性。

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

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

    选项菜单

    普通选项菜单

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

    XML代码:

    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <item android:id="@+id/option_normal_1"
            android:icon="@mipmap/ic_vpn_key_white_24dp"
            android:title="普通菜单1"
            app:showAsAction="ifRoom"/>
    
        <item android:id="@+id/option_normal_2"
            android:icon="@mipmap/ic_email_white_24dp"
            android:title="普通菜单2"
            app:showAsAction="always"/>
    
        <item android:id="@+id/option_normal_3"
            android:icon="@mipmap/ic_vpn_key_white_24dp"
            android:title="普通菜单3"
            app:showAsAction="withText|always"/>
    
        <item android:id="@+id/option_normal_4"
            android:title="普通菜单4"
            app:showAsAction="never"/>
    </menu>

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

    我们需要知道,菜单栏中的菜单项会分为两个部分。一部分可以直接在菜单栏中看见,我们可以称之为常驻菜单;另一部分会被集中收纳到溢出菜单中(就是菜单栏右侧的小点状图标)。一般情况下,常驻菜单项以图标形式显示(需要定义icon属性),而溢出菜单项则以文字形式显示(通过title属性定义)。showAsAction的差异如下所示:

    • always:菜单项永远不会被收纳到溢出菜单中,因此在菜单项过多的情况下可能超出菜单栏的显示范围。
    • ifRoom:在空间足够时,菜单项会显示在菜单栏中,否则收纳入溢出菜单中。
    • withText:无论菜单项是否定义了icon属性,都只会显示它的标题,而不会显示图标。使用这种方式的菜单项默认会被收纳入溢出菜单中。
    • never:菜单项永远只会出现在溢出菜单中。

    现在我们已经在XML文件中将Menu定义完毕了,接下来还需要在Java代码中进行加载,具体代码如下:

    Java代码:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater=getMenuInflater();
        inflater.inflate(R.menu.option_menu_normal,menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.option_normal_1:
                return true;
            case R.id.option_normal_2:
                return true;
            case R.id.option_normal_3:
                return true;
            case R.id.option_normal_4:
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    可以看见,我们在Activity中重写了onCreateOptionsMenu方法,在这个方法中完成加载Menu资源的操作,关键代码如下:

    //获取MenuInflater
    MenuInflater inflater=getMenuInflater();
    //加载Menu资源
    inflater.inflate(R.menu.option_menu_normal,menu);

    需要注意的是,这个方法必须返回true,否则Menu将不会显示。

    onOptionsItemSelected方法中,我们实现了菜单项的点击监听。可以看见,这里是通过MenuItemid进行区分的,对应着XML文件中<item>id属性。每次处理完点击事件后,记得要返回true,对系统而言这次点击事情才算是真正结束了。此外,在default分支下,推荐调用父类的默认实现,即super.onOptionsItemSelected(item),避免在多个Activity使用公有父类的情况下菜单项点击事件无法触发(下文会详细解释)。

    效果截图: 

    包含多级子菜单的选项菜单

    我们在前面提到过,<item>是可以嵌套<menu>的,而<menu>又是<item>的容器。因此,我们可以在应用中实现具有层级结构的子菜单。下面给出一个实际的例子:

    XML代码:

    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <item android:id="@+id/option_sub_file"
            android:title="文件"
            app:showAsAction="ifRoom">
            <menu>
                <item android:id="@+id/file_new"
                    android:title="新建"/>
                <item android:id="@+id/file_save"
                    android:title="保存"/>
    
                <item android:id="@+id/file_more"
                    android:title="更多">
                    <menu>
                        <item android:id="@+id/file_more_1"
                            android:title="更多1"/>
                        <item android:id="@+id/file_more_2"
                            android:title="更多2"/>
    
                        <item android:id="@+id/file_more_more"
                            android:title="更多更多">
                            <menu>
                                <item android:id="@+id/file_more_more_1"
                                    android:title="更多更多1"/>
                                <item android:id="@+id/file_more_more_2"
                                    android:title="更多更多2"/>
                            </menu>
                        </item>
                    </menu>
                </item>
            </menu>
        </item>
    </menu>

    上面的代码实现了一个三级子菜单结构。理论上来说,子菜单的层级是没有限制的。但是在实际应用中,由于移动设备的显示特点,建议菜单层级不要超过两层,否则会给用户的操作带来诸多不便。

    效果截图: 
     

    Activity+Fragment构建的选项菜单

    在前面,我们都是在Activity中加载Menu资源,实际上在Fragment中同样也可以做到这一点。如果Activity和Fragment都加载了Menu资源,那么这些菜单项将合并到一起。系统将首先显示Activity加载的菜单项,随后按每个Fragment添加到Activity中的顺序显示各Fragment的菜单项。如果有必要,可以使用<item>orderInCategory属性,对菜单项重新排序。

    实际上,在Fragment中加载Menu的方式和Activity几乎一致,同样需要重写onCreateOptionsMenuonOptionsItemSelected方法。当然,Fragment中的onCreateOptionsMenu方法有所不同,如下所示:

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.option_menu_fragment_2,menu);
    }

    还需要注意,要让Fragment中的菜单项显示出来,还需要在Fragment中调用setHasOptionsMenu(true)方法。传入true作为参数表明Fragment需要加载菜单项。建议在Fragment的onCreate方法中调用这个方法,如下所示:

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    当菜单项发生点击事件时,如果Activity包括Fragment,则系统将依次为Activity和每个Fragment(按照每个Fragment的添加顺序)调用onOptionsItemSelected方法,直到有一个返回结果为true或所有Fragment都调用完毕为止。因此,无论是Activity还是Fragment,onOptionsItemSelected方法中的switch语句块中的default分支都不要直接返回true,而应该使用return super.onOptionsItemSelected(item),避免截断了菜单项的点击事件。

    说明:详细代码可以参考下文提供的demo。

    在运行时修改的选项菜单

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

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

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

    下面我们提供一个简单的例子。在这个例子中:点击下一步后,上一步会被启用,下一步会被禁用;点击上一步后,下一步会被启用,上一步会被禁用。这是许多应用中常见的场景,代码如下:

    XML代码:

    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <item android:id="@+id/option_menu_previous"
            android:title="上一步"
            android:enabled="false"
            app:showAsAction="ifRoom"/>
    
        <item android:id="@+id/option_menu_next"
            android:title="下一步"
            android:enabled="true"
            app:showAsAction="ifRoom"/>
    </menu>

    我们在XML中定义了两个菜单项,默认启用下一步,禁用上一步

    Java代码:

    private boolean isShowNext=true;//当前是否显示[下一步]
    ......
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.option_menu_change,menu);
        return true;
    }
    
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if(isShowNext){//根据标识值判断当前应该启用哪个菜单项
            menu.findItem(R.id.option_menu_next).setEnabled(true);
            menu.findItem(R.id.option_menu_previous).setEnabled(false);
        }else{
            menu.findItem(R.id.option_menu_previous).setEnabled(true);
            menu.findItem(R.id.option_menu_next).setEnabled(false);
        }
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.option_menu_next:
                isShowNext=false;
                invalidateOptionsMenu();//通知系统刷新Menu
                return true;
            case R.id.option_menu_previous:
                isShowNext=true;
                invalidateOptionsMenu();//通知系统刷新Menu
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    在代码中,我们使用isShowNext这个布尔值标识当前可用的菜单项。在onOptionsItemSelected方法中,每次菜单项被点击后,我们会更改isShowNext,同时调用invalidateOptionsMenu通知系统刷新Menu。之后,onPrepareOptionsMenu会被调用。在这个方法中,我们根据isShowNext的值启用、禁用菜单项。可以看到,这里使用了Menu的findItem方法,它可以根据<item>的id获取对应的MenuItem对象,方法原型如下:

    public MenuItem findItem(int id);

    此外,还可以使用Menu的add方法添加新的菜单项(有多个重载方法)。

    效果截图: 
     

    使用公有父类构建选项菜单

    如果应用包含多个Activity,且其中某些Activity具有相同的选项菜单,则可考虑创建一个仅实现onCreateOptionsMenu和 onOptionsItemSelected方法的Activity。然后,将这个Activity作为每个具有相同选项菜单的Activity的父类。通过这种方式,每个子类均会继承父类的菜单行为。下面给出一个简单的例子:

    父类Activity中的XML代码:

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/option_menu_parent"
            android:title="父类菜单项"/>
    </menu>

    父类Activity中的Java代码:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.option_menu_parent,menu);
        return  true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.option_menu_parent:
                Toast.makeText(this,"父类菜单项",Toast.LENGTH_SHORT).show();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    子类Activity中的XML代码:

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/option_menu_child"
            android:title="子类菜单项"/>
    </menu>

    子类Activity中的Java代码:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);//调用这一句保证父类的菜单项可以正常加载
        getMenuInflater().inflate(R.menu.option_menu_child,menu);//加载子类自己的菜单项
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.option_menu_child:
                Toast.makeText(this,"子类菜单项",Toast.LENGTH_SHORT).show();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    可以看到,大部分代码都和创建普通的选项菜单一致。需要注意,在子类Activity的onCreateOptionsMenu方法中,我们首先调用了super.onCreateOptionsMenu(menu),保证父类的菜单项可以正常加载。然后,才对子类自己的菜单项进行加载。最终的效果就是在子类Activity中,既有父类的菜单项,也有自己的菜单项。

    需要注意,在子类的onOptionsItemSelected方法的default分支中,我们调用了父类的方法super.onOptionsItemSelected(item)。这是为了保证父类菜单项的点击行为可以被正确执行。当然,如果我们想要改变父类菜单项的行为,也可以在switch语句块中添加case进行重写。

    效果截图: 

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

    上下文菜单

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

    要提供浮动上下文菜单,可以参照以下步骤:

    1. 在Activity或Fragment中调用registerForContextMenu(View v)方法,注册需要和上下文菜单关联的View。如果将ListView或GridView作为参数传入,那么每个列表项将会有相同的浮动上下文菜单。
    2. 在Activity或Fragment中重写onCreateContextMenu方法,加载Menu资源。
    3. 在Activity或Fragment中重写onContextItemSelected方法,实现菜单项的点击逻辑。

    下面,我们演示如何为ListView设置浮动上下文菜单:

    XML代码:

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item android:id="@+id/context_option_add"
            android:title="添加"/>
        <item android:id="@+id/context_option_delete"
            android:title="删除"/>
        <item android:id="@+id/context_option_save"
            android:title="保存"/>
    </menu>

    Java代码:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_context_menu);
    
        //初始化ListView
        ListView listView= (ListView) findViewById(R.id.list_context_menu);
        ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1,createDataList());
        listView.setAdapter(adapter);
    
        //为ListView注册上下文浮动菜单
        registerForContextMenu(listView);
    }
    
    //生成测试数据List
    private List<String> createDataList(){
        List<String> list=new ArrayList<>();
        for(int i=0;i<10;i++){
            list.add("测试条目"+i);
        }
        return list;
    }
    
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        MenuInflater inflater=getMenuInflater();
        inflater.inflate(R.menu.context_menu,menu);
    }
    
    @Override
    public boolean onContextItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.context_option_add:
                Toast.makeText(this,"添加",Toast.LENGTH_SHORT).show();
                return true;
            case R.id.context_option_save:
                Toast.makeText(this,"保存",Toast.LENGTH_SHORT).show();
                return true;
            case R.id.context_option_delete:
                Toast.makeText(this,"删除",Toast.LENGTH_SHORT).show();
                return true;
            default:
                return super.onContextItemSelected(item);
        }
    }

    onCreateContextMenu方法中,方法参数包括用户所选的View,以及一个提供有关所选项目的附加信息的ContextMenu.ContextMenuInfo对象。如果需要为多个View设置不同的上下文菜单,则可使用这些参数确定要加载的上下文菜单资源。

    onContextItemSelected方法中,成功处理菜单项的监听事件后,系统将返回true。需要注意default分支中,应该调用super.onContextItemSelected(item)。如果Activity包括Fragment,则系统将依次为Activity和每个Fragment(按照每个Fragment的添加顺序)调用onContextItemSelected方法,直到有一个返回结果为true或所有Fragment都调用完毕为止。

    效果截图: 

    上下文操作模式

    上下文操作模式是ActionMode的系统实现,它将在屏幕顶部(菜单栏区域)显示上下文操作栏,其中包括影响所选项目的多种菜单项(通过加载Menu资源)。当启动这个模式时,用户可以同时对多个项目执行操作(批处理)。

    当用户取消选择所有项目、按“返回”按钮或选择操作栏左侧的“完成”操作时,该操作模式将会结束,同时上下文操作栏会消失。

    上下文操作模式的使用很灵活,既可以为单个View配置,也可以为ListView或GridView配置(允许用户选择多个项目并针对所有项目执行相应操作)。下面我们给出两个例子来说明上下文操作模式的使用。

    1.为ListView设置上下文操作模式

    简单来说,为ListView设置上下文操作模式可以分为两步:

    1. 使用CHOICE_MODE_MULTIPLE_MODAL参数调用ListView的setChoiceMode方法。
    2. 实现AbsListView.MultiChoiceModeListener接口,并调用ListView的setMultiChoiceModeListener方法为ListView设置该接口。在这个接口的回调方法中,可以为上下文操作栏加载Menu资源,也可以响应操作项目的点击事件,还可以处理其他需要的操作。

    下面给出相应的关键代码:

    XML代码:

    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <item android:id="@+id/context_mode_email"
            android:icon="@mipmap/ic_email_white_24dp"
            android:title="email"
            app:showAsAction="ifRoom"/>
        <item android:id="@+id/context_mode_key"
            android:icon="@mipmap/ic_vpn_key_white_24dp"
            android:title="key"
            app:showAsAction="ifRoom"/>
    </menu>

    Java代码:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_context_mode);
    
        //初始化ListView
        final ListView listView= (ListView) findViewById(R.id.list_context_menu);
        ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1,createDataList());
        listView.setAdapter(adapter);
    
        //为ListView配置上下文操作模式
        listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
        listView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
            @Override
            public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
                //当列表中的项目选中或取消勾选时,这个方法会被触发
                //可以在这个方法中做一些更新操作,比如更改上下文操作栏的标题
                //这里显示已选中的项目数
                mode.setTitle("已选中:"+listView.getCheckedItemCount()+"项");
            }
            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                MenuInflater inflater=mode.getMenuInflater();
                inflater.inflate(R.menu.context_mode_menu,menu);
                return true;
            }
            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                switch (item.getItemId()){
                    case R.id.context_mode_email:
                        Toast.makeText(ContextModeActivity.this,"email",Toast.LENGTH_SHORT).show();
                        mode.finish();//关闭上下文操作栏
                        return true;
                    case R.id.context_mode_key:
                        Toast.makeText(ContextModeActivity.this,"key",Toast.LENGTH_SHORT).show();
                        mode.finish();
                        return true;
                    default:
                        return false;
                }
            }
            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                //可以对上下文操作栏做一些更新操作(会被ActionMode的invalidate方法触发)
                return false;
            }
            @Override
            public void onDestroyActionMode(ActionMode mode) {
                //在上下文操作栏被移除时会触发,可以对Activity做一些必要的更新
                //默认情况下,此时所有的选中项将会被取消选中
            }
        });
    }
    
    //生成测试数据List
    private List<String> createDataList(){
        List<String> list=new ArrayList<>();
        for(int i=0;i<10;i++){
            list.add("测试条目"+i);
        }
        return list;
    }

    AbsListView.MultiChoiceModeListener接口中,最重要的就是onCreateActionModeonActionItemClicked两个方法。前者用于加载上下文操作模式的Menu资源,后者则实现菜单项的点击逻辑。需要注意,在onActionItemClicked中处理完相应的逻辑后,应该调用mode.finish,以便关闭上下文操作栏。

    效果截图: 

    2.为单个View设置上下文操作模式

    为单个View设置上下文操作模式同样可以分为两步:

    1. 实现ActionMode.Callback接口。在这个接口的回调方法中,可以为上下文操作栏加载Menu资源,也可以响应操作项目的点击事件,还可以处理其他需要的操作。
    2. 当需要显示操作栏时(例如,用户长按视图),调用Activity的startActionMode方法,并传入前面创建的Callback对象作为参数。

    下面给出相应的关键代码:

    private ActionMode actionMode;//在全局范围保存上下文操作模式实例
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_single_context_mode);
    
        //实现ActionMode.CallBack接口
        final ActionMode.Callback callback=new ActionMode.Callback() {
            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                MenuInflater inflater=mode.getMenuInflater();
                inflater.inflate(R.menu.context_mode_menu,menu);
                return true;
            }
            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                switch (item.getItemId()){
                    case R.id.context_mode_email:
                        Toast.makeText(SingleContextModeActivity.this,"email",Toast.LENGTH_SHORT).show();
                        mode.finish();//关闭上下文操作栏
                        return true;
                    case R.id.context_mode_key:
                        Toast.makeText(SingleContextModeActivity.this,"key",Toast.LENGTH_SHORT).show();
                        mode.finish();
                        return true;
                    default:
                        return false;
                }
            }
            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                return false;
            }
            @Override
            public void onDestroyActionMode(ActionMode mode) {
                actionMode=null;//取消保存的ActionMode实例,避免影响下一次ActionMode的创建
            }
        };
        //为按钮配置上下文操作模式
        findViewById(R.id.context_mode_view).setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if(actionMode!=null){
                    return false;
                }
                actionMode=startActionMode(callback);
                v.setSelected(true);//设置View的状态为选中
                return true;
            }
        });
    }

    上面的大部分代码都和为ListView设置上下文操作模式一致。只是在onDestroyActionMode方法中,执行了actionMode=null,这是为了避免影响下一次ActionMode的创建。此外,我们为目标View设置了OnLongClickListener,在回调方法中为全局范围的ActionMode赋值,并调用setSelected(true)方法设置View的状态为选中。

    需要说明的是,ListView中的项目在选中后呈现的状态(一般会使用深色强调选中项),需要在Adapter中单独配置。在上面的例子中并没有实现这一步,因此选中多项后ListView的外观并不会发生变化。

    效果截图: 

    弹出菜单

    PopupMenu是依赖View存在的模态菜单。如果空间足够,它将显示在相应View的下方,否则显示在其上方。可以将弹出菜单的使用拆分为以下四个步骤:

    1. 实例化PopupMenu,它的构造方法需要两个参数,分别为Context以及PopupMenu依赖的View对象。
    2. 使用MenuInflater将Menu资源加载到PopupMenu.getMenu()返回的Menu对象中。
    3. 调用setOnMenuItemClickListener方法为PopupMenu设置点击监听器。
    4. 调用PopupMenu.show()将弹出菜单显示出来。

    下面给出一个简单的例子:

    XML代码:

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/popup_add"
            android:title="添加"/>
        <item android:id="@+id/popup_delete"
            android:title="删除"/>
        <item android:id="@+id/popup_more"
            android:title="更多"/>
    </menu>

    Java代码:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_popup_menu);
    
        findViewById(R.id.popup_menu_view).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                PopupMenu popupMenu=new PopupMenu(PopupMenuActivity.this,view);//1.实例化PopupMenu
                getMenuInflater().inflate(R.menu.popup_menu,popupMenu.getMenu());//2.加载Menu资源
    
                //3.为弹出菜单设置点击监听
                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem item) {
                        switch (item.getItemId()){
                            case R.id.popup_add:
                                Toast.makeText(PopupMenuActivity.this,"添加",Toast.LENGTH_SHORT).show();
                                return true;
                            case R.id.popup_delete:
                                Toast.makeText(PopupMenuActivity.this,"删除",Toast.LENGTH_SHORT).show();
                                return true;
                            case R.id.popup_more:
                                Toast.makeText(PopupMenuActivity.this,"更多",Toast.LENGTH_SHORT).show();
                                return true;
                            default:
                                return false;
                        }
                    }
                });
                popupMenu.show();//4.显示弹出菜单
            }
        });
    }

    当用户选择菜单项或触摸菜单以外的区域时,系统就会清除弹出菜单,可以使用PopupMenu.OnDismissListener监听这一事件。

    效果截图: 

    菜单组

    我们在前面曾经提到过<group>这种元素,使用<group>可以对菜单项进行分组。对于同一个<group>中的<item>,可以通过menu执行以下操作:

    • 使用setGroupVisible显示或隐藏组内的所有项目
    • 使用setGroupEnabled启用或禁用组内的所有项目
    • 使用setGroupCheckable指定组内的所有项目是否可选中

    这三个方法的原型如下:

    public void setGroupVisible(int group, boolean visible);
    public void setGroupEnabled(int group, boolean enabled);
    public void setGroupCheckable(int group, boolean checkable, boolean exclusive);

    参数中的group指的是<group>元素的id属性。此外,setGroupCheckable方法中的exclusive用于设置菜单项的选择模式。如果exclusive为true,代表菜单项为单选模式,否则为多选模式。

    需要注意,<group>只是一种逻辑上的分组,并不会影响<item>的外观和级别。此外,系统也绝不会分离已分组的项目。例如,如果为同一组内的每个<item>声明android:showAsAction="ifRoom",则它们会同时显示在操作栏或操作溢出菜单中。

    下面是一个简单的例子:

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/group_menu_normal"
            android:title="普通项"/>
    
        <item android:id="@+id/group_menu_normal"
            android:title="普通项"/>
    
        <group android:id="@+id/group_menu_1"
            android:checkableBehavior="single">
            <item android:id="@+id/group_menu_item_1"
                android:title="组内项1"/>
            <item android:id="@+id/group_menu_item_2"
                android:title="组内项2"/>
        </group>
    </menu>

    可选中的菜单项

    如果为<group>指定checkableBehavior属性,则可以为组内项目实现单选或多选的选择模式。checkableBehavior有三种可选值:

    • single:组中只有一个项目可以选中(单选按钮)
    • all:所有项目均可选中(复选框)
    • none:所有项目均无法选中

    下面给出一个简单的例子:

    XML代码:

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/group_menu_normal"
            android:title="普通项"/>
    
        <group android:id="@+id/group_menu_1"
            android:checkableBehavior="single">
            <item android:id="@+id/group_menu_item_1"
                android:title="单选组内项1"/>
            <item android:id="@+id/group_menu_item_2"
                android:title="单选组内项2"/>
        </group>
    
        <group android:id="@+id/group_menu_2"
            android:checkableBehavior="all">
            <item android:id="@+id/group_menu_item_3"
                android:title="多选组内项1" />
            <item android:id="@+id/group_menu_item_4"
                android:title="多选组内项2" />
        </group>
    </menu>

    Java代码:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_menu_group);
    
        //为按钮注册上下文菜单
        Button button= (Button) findViewById(R.id.group_menu_view);
        registerForContextMenu(button);
    }
    
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        getMenuInflater().inflate(R.menu.group_menu,menu);
    }
    
    @Override
    public boolean onContextItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.group_menu_normal:
            case R.id.group_menu_item_1:
            case R.id.group_menu_item_2:
            case R.id.group_menu_item_3:
            case R.id.group_menu_item_4:
                if(item.isChecked()){//更改菜单项的选中状态
                    item.setChecked(false);
                }else{
                    item.setChecked(true);
                }
                Toast.makeText(this,item.getTitle(),Toast.LENGTH_SHORT).show();
                return true;
            default:
                return super.onContextItemSelected(item);
        }
    }

    效果截图: 

    展开全文
  • 前言:这周看到菜单部分,以前也对菜单有过使用,但并没有系统的对菜单进行梳理。这次借着这个机会,对菜单进行梳理。但只是很浅显的系统讲解,即对菜单的种类及各种用法作了...2、《Menu详解(二):利用XML生成...
  • 【用法】menu

    2018-01-08 09:55:24
    1、加载menu @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.mainmenu,menu); return true; } 2、menu里的item对应的事件 @Override public boo
  • Menu的使用

    2016-08-19 13:37:15
    一、ActionBar的简单使用 ...1、在res文件夹下,创建menu文件夹,然后创建menu_main.xml 然后:在MainActivity加载menu视图 1、了解标签页下的子标签 :代表了菜单中一个选项。  图一的“搜索”按钮就代表
  • Menu菜单的使用

    2017-11-16 22:03:33
    修改res/menu/main.xml,如下: ifRoom表示:如果有空间,就显示出来。withText表示:只显示文本.always表示显示在标题栏 <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=
  • 相信大家在使用 Element UI 中 el-menu 组件的时候,都碰到过如何通过数据动态渲染的问题,而官方的文档却没有这个实例,网上找的一些博客大部分人都实现了 el-menu 的垂直模式,而水平模式却没有,并且垂直模式的 ...
  • ion-menu的使用

    2018-03-31 11:10:42
    直入主题,侧边栏ion-menu的使用首先新建一个page用来存放侧边栏的内容,这里新建...实现简单的侧边栏功能,这一页写上ion-menu标签和ion-nav标签就行,先介绍一下ion-menu标签里面属性。 ion-menu标签里的[content...
  • vue、Menu 导航菜单、Menu属性、vue Menu 全部导航菜单、vue Menu 全部属性设计规则何时使用代码演示顶部导航内嵌菜单缩起内嵌菜单只展开当前父级菜单垂直菜单主题切换菜单类型单文件递归菜单APIMenuMenu 事件Menu....
  • Menu(菜单)组件用于实现顶级菜单、下拉菜单和弹出菜单。 何时使用 Menu 组件? Menu 组件通常被用于实现应用程序上的各种菜单,由于该组件是底层代码实现,所以不建议你自行通过按钮和其他组件来实现菜单功能。 ...
  • 1、menu函数:产生菜单 2、用法说明  m = menu('title','n1','n2',......,'nn') 函数显示以字符串变量‘title’为标题的菜单,选项为字符串变量:‘n1’,......,返回所输入的值到m 3、举例说明 >> m = menu('登录...
  • 前言:上篇,我们说了有关...1、《Menu详解(一):代码实现系统菜单及子菜单》 2、《Menu详解(二):利用XML生成菜单和子菜单》 3、《Menu详解(三):使用上下文菜单》 一、XML布局 在我们新建工程时,系统...
  • 今天下去,需要添加一个menu,网上找了很多例子,通过参考设置,实现了menu的调用。 可是 轮到我新建工程,实现menu的时候,问题出现了。 我用的是平板电脑,系统是android4.0的,没有 菜单按键 ,我运行别人代码...
  • Menu

    2016-03-14 15:25:09
    菜单的基本使用官方APImenu-resource在Android中,菜单被分为如下三种,选项菜单(OptionsMenu)、上下文菜单(ContextMenu)和子菜单(SubMenu)OptionsMenu效果图说明 重写两个方法 public boolean ...
  • Android按键之Menu详解

    2014-12-23 19:36:14
    从上图可以看出Menu是一个父类接口,它下面有两个子类一个是ContextMenu:它表示是一个上下文菜单,SubMenu表示一个子菜单。它们都可以包含一个或多个的MenuItem菜单项 Menu接口定义了两个方法来添加菜单项和添加子...
  • Android之Menu基本使用(显示图标icon) 作为初学者,记录自己的学习经历,方便以后查阅,也希望能够给更多初学者提供帮助。 Menu基本使用步骤: 1、启用Menu; 2、设置menu点击事件; 3、设置Menu图标显示。 只要...
  • Thinkpad开机停在boot menu界面|进不了系统的解决方法平原流风操作系统, 系统维护1条评论【问题描述】:最近在将Thinkpad E430c的ubuntu系统重装成windows 7的过程中,出现了装好win7系统后,开机自动进入boot menu...
  • Python MenuBar Menu 添加

    2016-04-05 09:51:09
    这个例子是关于MenuBar和Menu的建立规则:1、首先要建立MenuBar对象,然后建立Menu对象2、将Menu对象添加到MenuBar对象中,用Append方法3、向Menu对象中添加子菜单项,也是用Append方法4、将Menu对象中的子菜单项与...
1 2 3 4 5 ... 20
收藏数 415,955
精华内容 166,382
关键字:

menu