向 DialogPreference 添加上下文菜单
Android SDK 类 DialogPreference 本身并不支持上下文菜单。以下是一个快速实现它们的技巧。
引言
偏好设置 API 为 Android 应用程序提供了编辑常见应用程序设置(如字符串、数值数据、布尔选项等)的标准化外观和感觉。但有些应用程序需要更复杂的界面,这时标准的 DialogPreference
类就派上用场了,它允许你将自己的对话框添加到偏好设置界面,从而收集任何你想要的数据。不幸的是,DialogPreference
没有提供任何易于访问的方式来显示上下文菜单,但对于某些用户界面来说,上下文菜单确实很有必要。
在本文中,我将介绍一种将上下文菜单添加到 DialogPreference
的简单方法,具体是在编辑字符串列表的偏好设置中。我假设读者已经熟悉偏好设置 API 的整体操作,因此会跳过诸如存储或检索字符串列表的方法等问题,而只展示与当前问题相关的代码。
背景
显示上下文菜单的常用方法是在你的 Activity
对象上调用 registerForContextMenu(View)
,然后重写 Activity 的 onCreateContextMenu(ContextMenu, View, ContextMenu.ContextMenuInfo)
方法来提供菜单所需的选项。下面是一个简单的例子
protected void onCreate (Bundle savedInstanceState)
{
// initialise content view here
registerForContextMenu (findViewById (R.id.my_list));
}
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
}
public boolean onContextItemSelected(MenuItem item)
{
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId())
{
// handle menu items here
}
}
不幸的是,由于在 DialogPreference
的上下文中没有可用的 Activity
对象,因此在这种情况下这实际上是不可行的。
解决方案
为了解决这个问题,有必要自行确定何时显示上下文菜单(例如,响应长按,或者像我在这里做的那样,响应列表中项目的选择),然后自行生成上下文菜单。
我的菜单有两个选项,一个是删除项目,另一个是将它移动到列表的顶部(我的应用程序中列表顶部的项目具有特殊状态,作为默认选择,因此你希望能够轻松地更改它)。因此,我的上下文菜单文件如下所示
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/delete" android:title="Delete" />
<item android:id="@+id/makeDefault" android:title="Make default" />
</menu>
在最终应用程序中,菜单项的标题应该理想地是字符串值引用,而不是硬编码的,当然。
为了显示此菜单,我需要一个实现 OnCreateContextMenuListener
接口的对象。因为我喜欢尽可能减少创建的类数量,所以我将在同一个对象中实现我稍后需要的另一个接口 - OnMenuItemClickListener
。
public class ContextMenuGenerator implements OnCreateContextMenuListener, OnMenuItemClickListener
{
private int position;
private ArrayAdapter<String> adapter;
public ContextMenuGenerator (int position, ArrayAdapter<String> adapter)
{
this.position = position;
this.adapter = adapter;
}
public void onCreateContextMenu (ContextMenu menu, View v, ContextMenuInfo menuInfo)
{
new MenuInflater(context).inflate (R.menu.string_list_preference_popup, menu);
for (int i = 0; i < menu.size (); i ++)
menu.getItem (i).setOnMenuItemClickListener (this);
}
public boolean onMenuItemClick (MenuItem item) { /* we'll define this later */ }
为了显示菜单,我们需要指定将此侦听器用于其关联的视图,在我的例子中,是对话框中的 ListView
。不幸的是,在创建 Dialog
时指定此操作会导致滚动跟踪出现一些问题,因此我们必须在显示上下文菜单之前立即执行此操作。完成此操作后,我们可以显示菜单,然后删除侦听器
private AdapterView.OnItemClickListener showItemMenu = new AdapterView.OnItemClickListener ()
{
public void onItemClick (AdapterView<?> list, View control, int position, long itemId)
{
list.setOnCreateContextMenuListener (new ContextMenuGenerator(position, adapter));
list.showContextMenuForChild (control);
list.setOnCreateContextMenuListener (null);
}
};
这只剩下处理菜单选项,我将把它留作读者的练习。