Android Floating Context Menu的使用方法
来源:互联网 发布:苏亚星多媒体教学软件 编辑:程序博客网 时间:2024/05/22 06:39
1. 概述
Android Context Menu有两种,即floating context menu和contextual action mode下的context menu。本文讨论前者,后者是在Android 3.0开始引入的。
2. 主要思路
要使用floating context menu,包括如下几个主要步骤(适用于Activity和Fragment):
- 对于要关联context menu的view,调用registerForContextMenu(View)进行注册;
- 重载onCreateContextMenu(),其目的在于创建具体的context menu;
- 重载onContextItemSelected(),其目的在于,选择了某一个context menu item的时候,进行适当的处理。
3. 示例
这里是以为ListView创建一个context menu为例,其中ListView部分的介绍,请参考“ListView的例子”。
为了保持文章或示例的独立性,我们把相关的代码全部贴出来。
3.1 应用的布局文件
<?xml version="1.0" encoding="utf-8"?><!-- hello_context_menu.xml --><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ListView android:id="@+id/list_view_id" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView></LinearLayout>
3.2 ListView中每一个元素的 布局文件
<!-- student_item.xml --><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:id="@+id/student_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" /> <TextView android:id="@+id/student_score" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /></LinearLayout>
3.3 上下文菜单的资源文件
<?xml version="1.0" encoding="utf-8"?><!-- context_menu.xml --><menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/first_context_menu_item" android:title="@string/first_context_menu_item"/> <item android:id="@+id/second_context_menu_item" android:title="@string/second_context_menu_item"/></menu>
3.4 字符串资源
<string name="first_context_menu_item">first item</string><string name="second_context_menu_item">second item</string>
3.5 Java代码
package com.example.hellocontextmenu;import java.util.ArrayList;import java.util.HashMap;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.ContextMenu;import android.view.MenuInflater;import android.view.MenuItem;import android.view.View;import android.view.ContextMenu.ContextMenuInfo;import android.widget.ListView;import android.widget.SimpleAdapter;public class MainActivity extends Activity { private static final String TAG = "MainActivity";@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.hello_context_menu); ListView listView = (ListView) this.findViewById(R.id.list_view_id); setData(listView); this.registerForContextMenu(listView); } private void setData(ListView listView) { // each item's layout resource id int student_item_id = R.layout.student_item; // columns names String[] columnNames = new String[] { "name", "score" }; // resource ids int[] ids = new int[] { R.id.student_name, R.id.student_score }; // the data to be displayed ArrayList<HashMap<String, Object>> students = new ArrayList<HashMap<String, Object>>(); HashMap<String, Object> map = null; for (int i = 1; i <= 10; i++) { map = new HashMap<String, Object>(); map.put(columnNames[0], "student-" + i); map.put(columnNames[1], String.valueOf(i * 10)); students.add(map); } listView.setAdapter(new SimpleAdapter(this, students, student_item_id, columnNames, ids)); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = this.getMenuInflater(); inflater.inflate(R.menu.context_menu, menu); } @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.first_context_menu_item: Log.d(TAG, "first context menu item selected"); return true; case R.id.second_context_menu_item: Log.d(TAG, "second context menu item selected"); return true; default:return super.onContextItemSelected(item); } }}
3.6 运行效果
4. 关于ContextMenuInfo
在Android官网的Menu Guide中,提到ContextMenuInfo可用于标识当前所选择的view,以及view中的item,从而做一些特殊的处理。原文如下:
The callback method parameters include the View that the user selected and a ContextMenu.ContextMenuInfo object that provides additional information about the item selected. If your activity has several views that each provide a different context menu, you might use these parameters to determine which context menu to inflate.
本节就来分析这个ContextMenuInfo,并通过一些例子进行说明。
4.1 ContextMenuInfo接口
先大概了解这个对象,查看ContextMenuInfo这个class,发现有个toString()方法。增加调试打印:
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = this.getMenuInflater(); inflater.inflate(R.menu.context_menu, menu); Log.d(TAG, menuInfo.toString()); }
运行结果如下:
android.widget.AdapterView$AdapterContextMenuInfo@41d217b8
实际上,这个toString()并不是ContextMenuInfo重载的,而是缺省的继承Object的该方法。ContextMenuInfo本身是一个接口:
/** * Additional information regarding the creation of the context menu. For example, * {@link AdapterView}s use this to pass the exact item position within the adapter * that initiated the context menu. */ public interface ContextMenuInfo { }
4.2 AdapterView
本例使用的是ListView,而它是(间接)继承自AdapterView。在AdapterView中,定义了ContextMenuInfo的一个实现,即AdapterContextMenuInfo:
/** * Extra menu information provided to the * {@link android.view.View.OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo) } * callback when a context menu is brought up for this AdapterView. * */ public static class AdapterContextMenuInfo implements ContextMenu.ContextMenuInfo { public AdapterContextMenuInfo(View targetView, int position, long id) { this.targetView = targetView; this.position = position; this.id = id; } /** * The child view for which the context menu is being displayed. This * will be one of the children of this AdapterView. */ public View targetView; /** * The position in the adapter for which the context menu is being * displayed. */ public int position; /** * The row id of the item for which the context menu is being displayed. */ public long id; }
这里的targetView、position、id就是典型的各种适配器中的概念。由此,我们就可以确定前面提到的onCreateContextMenu()及onContextItemSelected()中menuInfo对象的详细数据了。
4.3 分析ContextMenuInfo对象
根据前面的分析,我们可以根据所选择的ListView中的具体数据,来加载不同的context menu,——对应onCreateContextMenu()。还可以在onContextItemSelected()中对具体的选中对象做特殊的处理。下面的就是Android官网Menu Guide中的示例代码:
@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); }}
5. ContextMenuInfo的使用示例
我们接下来在之前的代码增加一些处理:根据选择的不同的对象,inflater不同的context menu:共3种,除了之前的一种之外,另增加了更新学生分数的两个上下文菜单。
5.1 增加学生分数的menu资源
<?xml version="1.0" encoding="utf-8"?><!-- add_context_menu.xml --><menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/add_score" android:title="@string/add_score"/></menu>
5.2 减少学生分数的menu资源
<?xml version="1.0" encoding="utf-8"?><!-- minus_context_menu.xml --><menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/minus_score" android:title="@string/minus_score"/></menu>
5.3 新增的字符串资源
<string name="add_score">Add Score</string><string name="minus_score">Minus Score</string>
5.4 Java代码
package com.example.hellocontextmenu;import java.util.ArrayList;import java.util.HashMap;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.ContextMenu;import android.view.MenuInflater;import android.view.MenuItem;import android.view.View;import android.view.ContextMenu.ContextMenuInfo;import android.widget.AdapterView.AdapterContextMenuInfo;import android.widget.BaseAdapter;import android.widget.ListView;import android.widget.SimpleAdapter;import android.widget.Toast;public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private ListView listView = null; private BaseAdapter adapter = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.hello_context_menu); listView = (ListView) this.findViewById(R.id.list_view_id); setData(); this.registerForContextMenu(listView); } private void setData() { // each item's layout resource id int student_item_id = R.layout.student_item; // columns names String[] columnNames = new String[] { "name", "score" }; // resource ids int[] ids = new int[] { R.id.student_name, R.id.student_score }; // the data to be displayed ArrayList<HashMap<String, Object>> students = new ArrayList<HashMap<String, Object>>(); HashMap<String, Object> map = null; for (int i = 1; i <= 10; i++) { map = new HashMap<String, Object>(); map.put(columnNames[0], "student-" + i); map.put(columnNames[1], String.valueOf(i * 10)); students.add(map); } adapter = new SimpleAdapter(this, students, student_item_id, columnNames, ids); listView.setAdapter(adapter); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo; dumpInfo(info); MenuInflater inflater = this.getMenuInflater(); if (info.position > 8) { inflater.inflate(R.menu.context_menu, menu); } else { if (info.position % 2 == 0) { inflater.inflate(R.menu.add_context_menu, menu); } else { inflater.inflate(R.menu.minus_context_menu, menu); } } } private void dumpInfo(AdapterContextMenuInfo info) { HashMap<String, Object> student = (HashMap<String, Object>) adapter.getItem(info.position); Toast.makeText(this, student.toString(),Toast.LENGTH_LONG).show();} private void updateScore(ContextMenuInfo menuInfo, int incremental) { AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;HashMap<String, Object> student = (HashMap<String, Object>) adapter.getItem(info.position);Log.d(TAG, "old: " + student.toString());String studentName = (String) student.get("name");String studentScore = (String) student.get("score");int score = Integer.parseInt(studentScore);student.put("score", String.valueOf(score + incremental));adapter.notifyDataSetChanged();Log.d(TAG, "new: " + student.toString());} @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.first_context_menu_item: Log.d(TAG, "first context menu item selected"); return true; case R.id.second_context_menu_item: Log.d(TAG, "second context menu item selected"); return true; case R.id.add_score: updateScore(item.getMenuInfo(), 1); return true; case R.id.minus_score: updateScore(item.getMenuInfo(), -1); return true; default:return super.onContextItemSelected(item); } }}
5.5 运行效果
logcat日志:
09-07 20:17:29.835: D/MainActivity(13101): old: {score=20, name=student-2}09-07 20:17:29.835: D/MainActivity(13101): new: {score=19, name=student-2}09-07 20:17:40.745: D/MainActivity(13101): old: {score=40, name=student-4}09-07 20:17:40.745: D/MainActivity(13101): new: {score=39, name=student-4}09-07 20:18:02.755: D/MainActivity(13101): second context menu item selected09-07 20:18:11.265: D/MainActivity(13101): old: {score=10, name=student-1}09-07 20:18:11.265: D/MainActivity(13101): new: {score=11, name=student-1}
上下文菜单的截图:
6. 多个View的情况
现在前面代码的基础上,增加一个View。此时在onCreateContextMenu()中,通过传入的View参数来区分不同的View对象,从而加载不同的context menu。
6.1 布局文件
增加一个Button:
<?xml version="1.0" encoding="utf-8"?><!-- hello_context_menu.xml --><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/button_id" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/button_text"/> <ListView android:id="@+id/list_view_id" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView></LinearLayout>
6.2 字符串资源
<string name="button_text">Try to Click Me</string>
6.3 Java代码
主要修改两个地方:
- 为Button注册上下文菜单;
- 创建上下文菜单的时候,要区分不同的view,做差异化处理
package com.example.hellocontextmenu;import java.util.ArrayList;import java.util.HashMap;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.ContextMenu;import android.view.MenuInflater;import android.view.MenuItem;import android.view.View;import android.view.ContextMenu.ContextMenuInfo;import android.widget.AdapterView.AdapterContextMenuInfo;import android.widget.BaseAdapter;import android.widget.Button;import android.widget.ListView;import android.widget.SimpleAdapter;import android.widget.Toast;public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private ListView listView = null; private BaseAdapter adapter = null; private Button button = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.hello_context_menu); listView = (ListView) this.findViewById(R.id.list_view_id); setData(); button = (Button) this.findViewById(R.id.button_id); this.registerForContextMenu(button); this.registerForContextMenu(listView); Log.d(TAG, "onCreate()"); } private void setData() { // each item's layout resource id int student_item_id = R.layout.student_item; // columns names String[] columnNames = new String[] { "name", "score" }; // resource ids int[] ids = new int[] { R.id.student_name, R.id.student_score }; // the data to be displayed ArrayList<HashMap<String, Object>> students = new ArrayList<HashMap<String, Object>>(); HashMap<String, Object> map = null; for (int i = 1; i <= 10; i++) { map = new HashMap<String, Object>(); map.put(columnNames[0], "student-" + i); map.put(columnNames[1], String.valueOf(i * 10)); students.add(map); } adapter = new SimpleAdapter(this, students, student_item_id, columnNames, ids); listView.setAdapter(adapter); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = this.getMenuInflater(); if (v == button) { inflater.inflate(R.menu.context_menu, menu); return; } // Now the view is the ListView object AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo; dumpInfo(info); if (info.position % 2 == 0) {inflater.inflate(R.menu.add_context_menu, menu);} else {inflater.inflate(R.menu.minus_context_menu, menu);}} private void dumpInfo(AdapterContextMenuInfo info) { HashMap<String, Object> student = (HashMap<String, Object>) adapter.getItem(info.position); Toast.makeText(this, student.toString(),Toast.LENGTH_LONG).show();} private void updateScore(ContextMenuInfo menuInfo, int incremental) { AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;HashMap<String, Object> student = (HashMap<String, Object>) adapter.getItem(info.position);Log.d(TAG, "old: " + student.toString());String studentName = (String) student.get("name");String studentScore = (String) student.get("score");int score = Integer.parseInt(studentScore);student.put("score", String.valueOf(score + incremental));adapter.notifyDataSetChanged();Log.d(TAG, "new: " + student.toString());} @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.first_context_menu_item: Log.d(TAG, "first context menu item selected"); return true; case R.id.second_context_menu_item: Log.d(TAG, "second context menu item selected"); return true; case R.id.add_score: updateScore(item.getMenuInfo(), 1); return true; case R.id.minus_score: updateScore(item.getMenuInfo(), -1); return true; default:return super.onContextItemSelected(item); } }}
6.4 使用习惯
以上我们为Button注册上下文菜单,仅仅是一种示例,用于说明如何区分不同的View对象。
虽然可以给各种View注册上下文菜单,但从用户使用习惯上来讲,我们通常只会为特定的一些类别注册这种行为。比如给编辑框注册,长按之后可以Select/SelectAll/Copy/Paste;另外更常见的是ListView, GridView等。
7. 小结
从本文示例来看,floating context menu使用起来还是很方便的。当然,其功能还是有一定的局限性,为此Android3.0引入了contextual action mode的概念。
- Android Floating Context Menu的使用方法
- Android Contextual Menus之一:floating context menu
- Creating a floating context menu上下文菜单
- Android menu的使用方法
- android的Context Menu菜单
- Android的context menu组件
- Android Popup Menu的使用方法
- Android Custom View---Floating Action Button Menu
- Android 的上下文菜单: Context Menu
- Android 的上下文菜单: Context Menu
- Android 的上下文菜单: Context Menu
- Android 的上下文菜单: Context Menu
- Android 的上下文菜单: Context Menu
- Android 的上下文菜单: Context Menu
- android的上下文菜单---context menu
- Android 的上下文菜单: Context Menu
- android的上下文菜单---context menu
- Android Context Menu和Options Menu菜单的区别
- 数据库进阶系列之二:细说数据库范式
- epplus概要说明
- Centos6.5系统初学者基本系统配置1
- 去掉最大值、最小值之后剩下的个数(华为上机试题8_29_1)
- 数据结构 三种简单的排序(插入、选择、冒泡)
- Android Floating Context Menu的使用方法
- 关于Java多线程和并发运行的学习(一)
- javaMD5值加密代码!
- java异常处理之throw, throws,try和catch
- GreenDao 学习笔记 4
- Linux workqueue工作原理
- Mac显示/隐藏文件的终端命令
- 详解kettle之User Defined Java Class步骤(一)
- sql之left join、right join、inner join的区别