La detección de qué elemento seleccionado (en un ListView) engendró el ContextMenu (Android)

Tengo un ListView que permitirá al usuario presionar prolongadamente un elemento para obtener un menú contextual. El problema que estoy teniendo es determinar qué ListItem presionaron durante mucho tiempo. He intentado hacer esto:

 myListView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { @Override public void onCreateContextMenu(ContextMenu menu, final View v, ContextMenuInfo menuInfo) { menu.add("Make Toast") .setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { String toastText = "You clicked position " + ((ListView)v).getSelectedItemPosition(); Toast.makeText(DisplayScheduleActivity.this, toastText, Toast.LENGTH_SHORT).show(); return true; } }); } }); 

pero simplemente se cuelga hasta que aparece un ANR . Sospecho que después de crear el menú, ListItem ya no se selecciona.

Parece que podría supervisar los clics o los clics largos y luego registrar el elemento cliqueado allí:

  mArrivalsList.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView parent, View v, int position, long id) { // record position/id/whatever here return false; } }); 

pero eso se siente mayormente kludgey para mí. ¿Alguien tiene mejores soluciones para esto?

Yo hago exactamente esto. En mi onCreateContextMenu(...) , AdapterView.AdapterContextMenuInfo ContextMenu.ContextMenuInfo a AdapterView.AdapterContextMenuInfo . A partir de ahí, puede obtener el targetView, que vuelve a transmitir al widget. El código completo está disponible en HomeActivity.java , busque el onCreateContextMenu(...) .

 @Override public void onCreateContextMenu(ContextMenu contextMenu, View v, ContextMenu.ContextMenuInfo menuInfo) { AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; selectedWord = ((TextView) info.targetView).getText().toString(); selectedWordId = info.id; contextMenu.setHeaderTitle(selectedWord); contextMenu.add(0, CONTEXT_MENU_EDIT_ITEM, 0, R.string.edit); contextMenu.add(0, CONTEXT_MENU_DELETE_ITEM, 1, R.string.delete); } 

Tenga en cuenta que almaceno el texto seleccionado, así como la identificación de selección en campos privados. Dado que la interfaz de usuario está limitada por hilos, sé que los campos SelectedWord y selectedWordId serán correctos para acciones posteriores.

Antes que nada, me pregunto si estás complicando un poco las cosas usando View.setOnCreateContextMenuListener() . Las cosas se vuelven mucho más fáciles si usa Activity.registerForContextMenu() , porque entonces simplemente puede usar Activity.onCreateContextMenu() y Activity.onContextItemSelected() para manejar todos sus eventos de menú. Básicamente significa que no tiene que definir todas estas clases internas anónimas para manejar cada evento; solo necesita anular algunos métodos de Actividad para manejar estos eventos del menú contextual.

En segundo lugar, definitivamente hay formas más fáciles de recuperar el elemento seleccionado actualmente. Todo lo que necesita hacer es mantener una referencia ya sea al ListView o al Adapter utilizado para poblarlo. Puede usar ContextMenuInfo como AdapterContextMenuInfo para obtener la posición del artículo; y luego puede usar ListView.getItemAtPosition() o Adapter.getItem() para recuperar el Object específicamente vinculado a lo que se hizo clic. Por ejemplo, suponiendo que estoy usando Activity.onCreateContextMenu() , podría hacer esto:

 @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); // Get the info on which item was selected AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; // Get the Adapter behind your ListView (this assumes you're using // a ListActivity; if you're not, you'll have to store the Adapter yourself // in some way that can be accessed here.) Adapter adapter = getListAdapter(); // Retrieve the item that was clicked on Object item = adapter.getItem(info.position); } @Override public boolean onContextItemSelected(MenuItem item) { // Here's how you can get the correct item in onContextItemSelected() AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); Object item = getListAdapter().getItem(info.position); } 

esta es otra manera de cómo crear el menú contextual n cómo eliminar el elemento seleccionado aquí es el código completo

  public class SimpleJokeList extends Activity { public static final int Upload = Menu.FIRST + 1; public static final int Delete = Menu.FIRST + 2; int position; ListView lv; EditText jokeBox; Button addJoke; MyAdapter adapter; private ArrayAdapter mAdapter; private ArrayList mStrings = new ArrayList(); String jokesToBeAdded; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simplejokeui); lv=(ListView)findViewById(R.id.jokelist); addJoke=(Button)findViewById(R.id.addjoke); jokeBox=(EditText)findViewById(R.id.jokebox); mAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, mStrings); registerForContextMenu(lv); listItemClicked(); addJokes(); private void addJokes() { // TODO Auto-generated method stub addJoke.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { // TODO Auto-generated method stub jokesToBeAdded=jokeBox.getText().toString(); if(jokesToBeAdded.equals("")){ Toast.makeText(getApplicationContext(), "please enter some joke", Toast.LENGTH_LONG).show(); } else{ lv.setAdapter(mAdapter); mAdapter.add(jokesToBeAdded); jokeBox.setText(null); } } }); } private void listItemClicked() { // TODO Auto-generated method stub lv.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView< ?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub position=arg2; return false; } }); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // TODO Auto-generated method stub super.onCreateContextMenu(menu, v, menuInfo); populateMenu(menu); menu.setHeaderTitle("Select what you wanna do"); } private void populateMenu(ContextMenu menu) { // TODO Auto-generated method stub menu.add(Menu.NONE, Upload, Menu.NONE, "UPLOAD"); menu.add(Menu.NONE, Delete, Menu.NONE, "DELETE"); } @Override public boolean onContextItemSelected(MenuItem item) { return (applyMenuChoice(item) || super.onContextItemSelected(item)); } private boolean applyMenuChoice(MenuItem item) { // TODO Auto-generated method stub switch (item.getItemId()) { case Delete: String s=mAdapter.getItem(position); mAdapter.remove(s); // position--; Toast.makeText(getApplicationContext(),"Congrats u HAve Deleted IT", Toast.LENGTH_LONG).show(); return (true); } return false; } 

Y no te olvides de poner esto

 registerForContextMenu(listview); 

en su método onCreate para que su Menú contextual onCreate visible.

Hemos utilizado con éxito:

 @Override public boolean onContextItemSelected ( MenuItem item ) { if (!AdapterView.AdapterContextMenuInfo.class.isInstance (item.getMenuInfo ())) return false; AdapterView.AdapterContextMenuInfo cmi = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo (); Object o = getListView ().getItemAtPosition (cmi.position); return true; } 

¿El argumento de la vista no es la vista de la fila seleccionada, o me falta la pregunta aquí?

 ListView lv; private OnItemLongClickListener onLongClick = new OnItemLongClickListener() { public boolean onItemLongClick(AdapterView< ?> arg0, View arg1, int arg2, long arg3) { lv.showContextMenuForChild(arg1); lv.showContextMenu(); return false; } }; 
 @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; View TargetV=(View) info.targetView; text1 = (String) ((TextView) TargetV.findViewById(R.id.textView1)).getText(); text2 = (String) ((TextView) TargetV.findViewById(R.id.textView2)).getText(); if(List3Ok){ text3 = (String) ((TextView) TargetV.findViewById(R.id.textView3)).getText(); } selectedWord = text1 + "\n" + text2 + "\n" + text3; selectedWordId = info.id; menu.setHeaderTitle(selectedWord); MenuInflater inflater = this.getActivity().getMenuInflater(); inflater.inflate(R.menu.list_menu, menu); } 

Si usa SimpleCursorAdapder , puede hacerlo así

  @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { getActivity().getMenuInflater().inflate(R.menu.project_list_item_context, menu); // Getting long-pressed item position AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; int position = info.position; // Get all records from adapter Cursor c = ((SimpleCursorAdapter)getListAdapter()).getCursor(); // Go to required position c.moveToPosition(position); // Read database fields values associated with our long-pressed item Log.d(TAG, "Long-pressed-item with position: " + c.getPosition()); Log.d(TAG, "Long-pressed-item _id: " + c.getString(0)); Log.d(TAG, "Long-pressed-item Name: " + c.getString(1)); Log.d(TAG, "Long-pressed-item Date: " + c.getString(2)); Log.d(TAG, "Long-pressed-item Path: " + c.getString(3)); // Do whatever you need here with received values }