我正在实现 ListActivity 和 ListFragment 并希望允许用户使用短按和长按 - 简短的是编辑/显示项目的详细信息,长按以调出带有删除项目选项的上下文菜单.但是,我似乎无法触发 onCreateContextMenu。 onListItemClick 工作正常并捕获所有点击,无论是短的还是长的。 ListFragment 是使用稍微自定义的 SimpleCursorAdaptor 和 LoaderManager 填充的,而不是使用布局文件。
有可能两者兼得吗?
代码...
LocationsListFragment.java
package com.level3.connect.locations;
//import removed for brevity
public class LocationsListFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor>{
private static final int DELETE_ID = Menu.FIRST + 1;
private SimpleCursorAdapter adapter;
private OnLocationSelectedListener locationSelectedListener;
// the activity attaching to this fragment should implement this interface
public interface OnLocationSelectedListener {
public void onLocationSelected(String locationId);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Fields from the database (projection)
// Must include the _id column for the adapter to work
String[] from = new String[] { LocationsTable.LOCATION_NAME,
LocationsTable.LOCATION_PHONE_NAME };
// Fields on the UI to which we map
int[] to = new int[] { R.id.titleText, R.id.phoneText };
// connect to the database
getLoaderManager().initLoader(0, null, this);
adapter = new LocationCursorAdapter(getActivity(),
R.layout.location_row, null, from, to, 0);
setListAdapter(adapter);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = super.onCreateView(inflater, container, savedInstanceState);
registerForContextMenu(root); //this is called fine
return root;
}
// hook up listening for the user selecting a location in the list
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
locationSelectedListener = (OnLocationSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnLocationSelectedListener");
}
}
// handle user tapping a location - show a detailed view - this works fine
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
String projection[] = { LocationsTable.KEY_ID };
Cursor locationCursor = getActivity().getContentResolver().query(
Uri.withAppendedPath(DatabaseContentProvider.CONTENT_URI,
String.valueOf(id)), projection, null, null, null);
if (locationCursor.moveToFirst()) {
String locationUrl = locationCursor.getString(0);
locationSelectedListener.onLocationSelected(locationUrl);
}
locationCursor.close();
}
// Context menu - this is never called
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}
@Override - this is never called
public boolean onContextItemSelected(android.view.MenuItem item) {
switch (item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
Uri uri = Uri.parse(DatabaseContentProvider.CONTENT_URI + "/"
+ info.id);
getActivity().getContentResolver().delete(uri, null, null);
return true;
}
return super.onContextItemSelected(item);
}
// Loader code
// Creates a new loader after the initLoader () call
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { LocationsTable.KEY_ID, LocationsTable.LOCATION_NAME, LocationsTable.LOCATION_PHONE_NAME };
CursorLoader cursorLoader = new CursorLoader(getActivity(),
DatabaseContentProvider.CONTENT_URI, projection, null, null, null);
return cursorLoader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// data is not available anymore, delete reference
adapter.swapCursor(null);
}
}
更新:我仍然没有弄清楚这一点,我想知道我是否必须放弃这个策略并以其他方式实现它,而不是用户友好的方式。也许滑动查看详细信息并点击删除?
最佳答案
我在 native 电子邮件应用程序的 Android 源代码中找到了答案。 https://android.googlesource.com/platform/packages/apps/Email/
ListFragment 必须实现监听器:
public class MessageListFragment extends SherlockListFragment
implements LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemLongClickListener
private static final int DELETE_ID = Menu.FIRST + 1;
private SimpleCursorAdapter adapter;
// The LoaderManager needs initializing
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Fields from the database (projection)
// Must include the _id column for the adapter to work
String[] from = new String[] { BookmarksTable.BOOKMARK_NAME,
BookmarksTable.BOOKMARK_PHONE_NAME };
// Fields on the UI to which we map
int[] to = new int[] { R.id.titleText, R.id.phoneText };
// connect to the database
getLoaderManager().initLoader(0, null, this);
adapter = new BookmarkCursorAdapter(getActivity(),
R.layout.bookmark_row, null, from, to, 0);
setListAdapter(adapter);
}
// register to put up the context menu
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = super.onCreateView(inflater, container, savedInstanceState);
registerForContextMenu(root);
return root;
}
// set the listeners for long click
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
getListView().setOnItemLongClickListener(this);
}
调用的方法是:
/**
* Called when a message is clicked.
*/
@Override
public void onListItemClick(ListView parent, View view, int position, long id) {
// do item click stuff; show detailed view in my case
}
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
return false; // let the system show the context menu
}
// Context menu
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}
// respond to the context menu tap
@Override
public boolean onContextItemSelected(android.view.MenuItem item) {
switch (item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
Uri uri = Uri.parse(DatabaseContentProvider.BOOKMARK_ID_URI + Long.toString(info.id));
getActivity().getContentResolver().delete(uri, null, null);
return true;
}
return super.onContextItemSelected(item);
}
为了完整起见,这是加载程序代码
// Loader code
// Creates a new loader after the initLoader () call
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { BookmarksTable.KEY_ID, BookmarksTable.BOOKMARK_NAME, BookmarksTable.BOOKMARK_PHONE_NAME };
CursorLoader cursorLoader = new CursorLoader(getActivity(),
DatabaseContentProvider.BOOKMARKS_URI, projection, null, null, null);
return cursorLoader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// data is not available anymore, delete reference
adapter.swapCursor(null);
}
关于Android ListFragment : how to have both onListItemClick and onContextItemSelected?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16348456/