Android Contextual Menus之一:floating context menu

时间:2022-08-10 21:36:40

Android Contextual Menus之一:floating context menu

上下文菜单

  上下文相关的菜单(contextual menu)用来提供影响UI中特定item或者context frame的动作。

  你可以为任何View提供上下文菜单,但是最常见的使用场景是在ListView、GridView或者其他集合类控件中的项目上,这样用户就可以对特定的项目执行一些直接的操作。

  有两种方式来提供上下文相关的动作:

  1.用悬浮上下文菜单( floating context menu)。

  当用户在支持上下文菜单的View上执行长按动作的时候,菜单以一种悬浮列表的方式出现,类似于对话框。

  用户可以每次选择一个菜单项,执行一个上下文相关的动作。

  2.用上下文相关的动作模式(contextual action mode)。

  这种模式是ActionMode的系统实现,在屏幕上方展示一个上下文相关的action bar,里面有一些action items,可以用来执行选定项目的相关动作。

  当这种模式active时,用户可以一次对多个项目执行操作。

  注意:虽然contextual action mode是更为推崇的一种方式,但是它是Android 3.0(API Level 11)之后才有的,如果要兼容3.0之前的系统,那就应该用floating context menu。

创建floating context menu

  提供悬浮上下文菜单的步骤如下:

  1.通过调用registerForContextMenu()方法注册上下文菜单相关的View。

  如果你的activity中用了ListView或者GridView,而且你想其中的每一个item都提供相同的上下文菜单,那么你可以在registerForContextMenu() 中传递这个ListView或GridView。

  2.在Activity或Fragment中实现 onCreateContextMenu()方法。

  当注册过的View接收到长按事件,系统会调用onCreateContextMenu()方法。

  这里你可以定义菜单项,通常是inflate一个菜单资源,比如:

@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允许你通过inflate menu resource来得到一个上下文菜单。

  这个回调方法的参数包含了一个用户选择的View和一个ContextMenu.ContextMenuInfo对象,该对象提供了当前选择的item的一些附加信息。

  如果你的activity有多个views,每个提供不同的上下文菜单,你可以用这些参数来决定当前要inflate那个上下文菜单。

  3.实现onContextItemSelected()方法

  当用户选择了一个菜单项,系统会调用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值。

  当成功处理了一个菜单项之后,返回true。

  如果你没有处理一个菜单项,你应该把这个菜单项转给它的基类实现。

  如果你的activity包含fragment,activity先接收到这个回调。

  当未处理而调用基类实现时,系统会将这个事件传递到每个fragment各自相应的回调方法中,按照fragment添加的顺序,每次一个,直到返回true或者false。

  Activity和Fragment的默认实现都是返回false,所以你应该永远在未处理的时候调用基类实现。

一个简单的例子

  实现的效果就是长按TextView之后显示一个上下文菜单,含两个菜单项,点击菜单项之后显示Toast。

  Activity代码:

package com.example.mengdd.hellocontextmenu;

import android.os.Bundle;
import android.app.Activity;
import android.view.ContextMenu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.TextView;
import android.widget.Toast; public class HelloContextMenuMainActivity extends Activity { private TextView mTextView1 = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hello_context_menu_main); mTextView1 = (TextView) findViewById(R.id.textView1); // 注册要弹出ContextMenu的View
registerForContextMenu(mTextView1); } @Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
// 第二个参数为当前点击的view super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getMenuInflater();
// 把布局inflate进menu对象
inflater.inflate(R.menu.context_menu1, menu);
} @Override
public boolean onContextItemSelected(MenuItem item) { boolean result = false;
switch (item.getItemId()) {
case R.id.edit: Toast.makeText(HelloContextMenuMainActivity.this, "Edit",
Toast.LENGTH_LONG).show();
result = true;
break;
case R.id.help:
Toast.makeText(HelloContextMenuMainActivity.this, "Help",
Toast.LENGTH_LONG).show();
result = true;
break;
default:
result = super.onContextItemSelected(item);
break; } return result; } }

  Activity的内容布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".HelloContextMenuMainActivity" > <TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" /> </LinearLayout>

  Menu的布局:

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

参考资料

  API Guides: Menus->Creating Contextual Menus

  http://developer.android.com/guide/topics/ui/menus.html#context-menu