虚位以待(AD)
虚位以待(AD)
首页 > 软件编程 > Android编程 > Android之Menu

Android之Menu
类别:Android编程   作者:码皇   来源:互联网   点击:

在Android3 0(API级别11)以下版本,当用户按“菜单”按钮时,选项菜单的内容会出现在屏幕底部,如图 1 所示。打开时,第一个可见部分是图标菜单,其中包含多达 6 个菜单项。 如果菜单包括 6 个以上项目,则 Android 会将第六项和其余项目放入溢出菜单。

Android中有各种各样的菜单,Android的菜单栏(也叫操作栏):ActionBar。先来看下Menu大汇总。
具体可看该网址:https://developer.android.com/guide/topics/ui/menus.html

普通菜单

在Android3.0(API级别11)以下版本,当用户按“菜单”按钮时,选项菜单的内容会出现在屏幕底部,如图 1 所示。打开时,第一个可见部分是图标菜单,其中包含多达 6 个菜单项。 如果菜单包括 6 个以上项目,则 Android 会将第六项和其余项目放入溢出菜单。用户可以通过选择“更多”打开该菜单。
这里写图片描述

在Android3.0及更高版本的系统中,选项菜单中的项目将出现在操作栏中。默认情况下,系统会将所有项目均放入操作溢出菜单中。用户可以使用操作栏右侧的操作溢出菜单图标(或者,通过按设备“菜单”按钮(如有))显示操作溢出菜单。 要支持快速访问重要操作,您可以将android:showAsAction=”ifRoom” 添加到对应的 元素,从而将几个项目提升到操作栏中。从 Android 3.0 开始,“菜单”按钮已弃用(某些设备没有该按钮),因此您应改为使用操作栏,来提供对操作和其他选项的访问。

这里写图片描述

对于上面两种形式的菜单,示例代码如下:

    @Overridepublic boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
    }
    @Overridepublic 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);
    }
    }

关于这种菜单的其他API,具体请自行上网查找。

上下文菜单

基于上面的菜单,Android出了新的菜单,也就是上下文菜单,先看下上下文菜单的效果图。

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

使用浮动上下文菜单。用户长按(按住)一个声明支持上下文菜单的视图时,菜单显示为菜单项的浮动列表(类似于对话框)。 用户一次可对一个项目执行上下文操作。(图中左边的菜单)使用上下文操作模式。此模式是 ActionMode 的系统实现,它将在屏幕顶部显示上下文操作栏,其中包括影响所选项的操作项目。当此模式处于活动状态时,用户可以同时对多项执行操作(如果应用允许)。(图中右边的菜单)

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

创建浮动上下文菜单:

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

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

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

    @Overridepublic 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 有多个视图,每个视图均提供不同的上下文菜单,则可使用这些参数确定要扩充的上下文菜单。

实现 onContextItemSelected()。
用户选择菜单项时,系统将调用此方法,以便您能够执行适当的操作。 例如:
    @Overridepublic 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,因此您始终应在未处理的情况下调用超类。)
示例代码如下:

    public class MainActivity extends AppCompatActivity {
    @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    registerForContextMenu(findViewById(R.id.btn_menu));
    }
    @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main, menu);
    }
    @Override public boolean onContextItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.menu_home: Toast.makeText(MainActivity.this, "menu_home", Toast.LENGTH_SHORT).show();
    break;
    case R.id.menu_recyclerview: Toast.makeText(MainActivity.this, "menu_recyclerview", Toast.LENGTH_SHORT).show();
    break;
    }
    return true;
    }
    }

使用上下文操作模式

上下文操作模式是 ActionMode 的一种系统实现,它将用户交互的重点转到执行上下文操作上。用户通过选择项目启用此模式时,屏幕顶部将出现一个“上下文操作栏”,显示用户可对当前所选项执行的操作。
注:上下文操作栏不一定与操作栏相关联。 尽管表面上看来上下文操作栏取代了操作栏的位置,但事实上二者独立运行。
为单个视图启用上下文操作模式如果希望仅当用户选择特定视图时才调用上下文操作模式,则应:

实现 ActionMode.Callback 接口。在其回调方法中,您既可以为上下文操作栏指定操作,又可以响应操作项目的点击事件,还可以处理操作模式的其他生命周期事件。当需要显示操作栏时(例如,用户长按视图),请调用 startActionMode()。
示例代码:
实现 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 或片段中的成员变量有何作用。

调用 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 实例已激活时不再重建该实例。
完整的示例代码:

    public class MainActivity extends AppCompatActivity implements android.view.ActionMode.Callback {
    private android.view.ActionMode mActionMode;
    @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findViewById(R.id.btn_menu_context).setOnLongClickListener(new View.OnLongClickListener() {
    @Override public boolean onLongClick(View v) {
    if (mActionMode != null) {
    return false;
    }
    mActionMode = startActionMode(MainActivity.this);
    v.setSelected(true);
    return true;
    }
    }
    );
    }
    @Override public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) {
    MenuInflater inflater = mode.getMenuInflater();
    inflater.inflate(R.menu.main, menu);
    return true;
    }
    @Override public boolean onPrepareActionMode(android.view.ActionMode mode, Menu menu) {
    return false;
    }
    @Override public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) {
    switch (item.getItemId()) {
    case R.id.menu_home: Toast.makeText(MainActivity.this, "menu_home", Toast.LENGTH_SHORT).show();
    break;
    case R.id.menu_recyclerview: Toast.makeText(MainActivity.this, "menu_recyclerview", Toast.LENGTH_SHORT).show();
    break;
    }
    return true;
    }
    @Override public void onDestroyActionMode(android.view.ActionMode mode) {
    mActionMode = null;
    }
    }

在 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;
    }
    }
    );

PopupMenu

PopupMenu 是锚定到 View 的模态菜单。如果空间足够,它将显示在定位视图下方,否则显示在其上方。
提供类似于 Spinner 且不保留永久选择的下拉菜单。
注:PopupMenu 在 API 级别 11 及更高版本中可用。

如果使用 XML 定义菜单,则显示弹出菜单的方法如下:

实例化 PopupMenu 及其构造函数,该函数将提取当前应用的 Context 以及菜单应锚定到的 View。使用 MenuInflater 将菜单资源扩充到 PopupMenu.getMenu() 返回的 Menu 对象中。在 API 级别 14 及更高版本中,您可以改为使用 PopupMenu.inflate()。

例如,以下是一个使用 android:onClick 属性显示弹出菜单的按钮:

稍后,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();
    }
    @Overridepublic 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;
    }
    }

效果的话,就是和微信首页的加号按钮一样。
这里写图片描述

   
相关热词搜索: