Identificar la vista seleccionada en un ContextMenu (Android)

En Android, onContextItemSelected tiene un solo argumento MenuItem y por lo tanto no está claro cómo identificar la vista seleccionada. MenuItem.getMenuInfo proporciona acceso a Contextmenu.ContextMenuInfo , pero aunque ambas subclases conocidas proporcionan acceso a la vista de destino, no parece que haya un accesor en la interfaz.

Una alternativa es guardar la View proporcionada en onCreateContextMenu en una variable de clase privada que se basa en onCreateContextMenu no se vuelve a llamar en la actividad antes onContextItemSelected . Otra es usar el id de la View para el argumento itemId de ContextMenu.add . Si hacemos esto, necesitaríamos identificar la opción seleccionada del menú contextual usando su título (posiblemente internacionalizado).

¿Cuál es el mejor método para identificar la View seleccionada en onContextSelected ?

No existe un concepto como "identificar la vista seleccionada" para los menús de opciones o los menús contextuales de Android. Por lo tanto, es bastante difícil responder a su pregunta. Así que, voy a tomar algunas conjeturas.

Si al "identificar la vista seleccionada" quiere decir qué opción de menú se seleccionó, que es getItemId() en el MenuItem que se pasa a onOptionsItemSelected() o onContextItemSelected() .

Si al "identificar la vista seleccionada" quiere decir qué fila en un ListView fue la que pulsó larga para abrir el menú contextual, cast getMenuInfo() (llamado en el MenuItem ) a AdapterView.AdapterContextMenuInfo , a continuación, utilice el id o Los valores de position según corresponda en función de su adaptador. Vea aquí para un proyecto de ejemplo que utiliza esta técnica.

Si al "identificar la vista seleccionada" quiere decir que tiene más de un menú contextual no ListView en una actividad, no usaría esa técnica de IU.

Todo el punto de un menú contextual es que está asociado con una vista subyacente individual, y es claramente una limitación de diseño en Android que la asociación se pierde en la devolución de llamada 'onContextItemSelected'. Habilitar el toque largo en cualquier vista de tamaño suficiente parece perfectamente razonable como alternativa al clic con el botón derecho del ratón.

Como otros puestos han recomendado, para algunos contextos:

 AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); 

Es apropiado y el targetView es un punto de referencia útil.

Otra forma es subclase la vista y reemplazar 'getContextMenuInfo' para proporcionar la referencia de vista. Por ejemplo, un TextView sencillo:

 Paquete ...;

 Public class TextViewWithContext extends TextView {
     TextViewContextMenuInfo _contextMenuInfo = null;

     Public TextViewWithContext (Context context) {
         Super (contexto);
         _contextMenuInfo = new TextViewContextMenuInfo (this);
     }

     Public TextViewWithContext (Context context, AttributeSet attrs) {
         Super (contexto, attrs);
         _contextMenuInfo = new TextViewContextMenuInfo (this);
     }   

     Protected ContextMenuInfo getContextMenuInfo () {
         Return _contextMenuInfo;
     }

     Public boolean isContextView (ContextMenuInfo menuInfo) {
         Return menuInfo == (ContextMenuInfo) _contextMenuInfo;
     }

     Clase protegida TextViewContextMenuInfo implementa ContextMenuInfo {
         Protected TextView _textView = null;

         Protected TextViewContextMenuInfo (TextView textView) {
             _textView = textView;
         }
     }
 }

 ...
     @Anular
     Public boolean onContextItemSelected (Elemento MenuItem) {   

         ContextMenuInfo menuInfo = item.getMenuInfo ();

         If (textViewWithContext.isContextView (menuInfo) {
             ...
         }
     }

Por último, habría sido más útil si la clase de vista base hubiera asignado un objeto ContextInfo con una referencia inversa a la vista, en lugar de null como en la actualidad.

Class TestActivity extends Actividad {

 // create temp item here private ImageView tmpImageView = null; 

 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo){ super.onCreateContextMenu(menu, v, menuInfo); // initialize temp item mCurrentStatusImage = (ImageView) v.findViewById(R.id.rule_status); } public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case ENABLE_ID: // use temp item tmpImageView.setImageResource(android.R.drawable.presence_online); return super.onContextItemSelected(item); case DISABLE_ID: // use temp item tmpImageView.setImageResource(android.R.drawable.presence_invisible); return super.onContextItemSelected(item); default: return super.onContextItemSelected(item); } 

Fijé un problema similar fijando un groupID para el MenuItem basado en qué artículo lo envió por ejemplo:

  textview.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() { @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) { menu.setHeaderTitle("Context Menu"); menu.add(R.id.whateverviewclicked, RENAME_MENU_ITEM, 0, "Rename"); menu.add(R.id.whateverviewclicked, DELETE_MENU_ITEM, 1, "Delete"); } }); 

Esto le permitiría obtener el groupID en el onContextItemSelected:

 public boolean onContextItemSelected(MenuItem aItem) { int selectedViewID = aItem.getGroupId(); int selectedItem = aItem.getItemId(); }; 

Usted no tiene que usar el ID del recurso – usted puede utilizar cualquier int que usted quiera. ¡Funciona para mi!

En caso de que esté adjuntando ContextMenus a varias vistas que no están en un ListView (que es que no hay ningún adaptador subyacente a las vistas) y desea determinar qué vista fue presionado para acceder a ContextMenu el siguiente "hack" puede ser implementado. (Sería mejor si Android proporcionara un oyente que podría estar asociado con cada elemento).

El "hack" es que uno crea un miembro View privado mLastViewTouched en la clase y luego adjuntar el siguiente onTouchListener a todas las vistas que pueden generar un ContextMenu:

  private View.OnTouchListener onTouchListener = new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { mLastViewTouched = view; // Store a handle on the last view touched. This will be used to identify the view on which the Context Menu was launched return false; // We return false since this indicates that the touch was not handled and so it is passed down the stack to be handled appropriately } }; 

Por lo tanto, cuando se toca una vista mLastViewTouched se actualiza. Ahora en onContextItemSelected tendrás acceso a la vista que inició el ContextMenu.

Al construir su menú en OnCreateContextMenuListener o public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) implementación, puede configurar un MenuItem.OnMenuItemClickListener personalizado para cada elemento:

  addPhotosBtn.setOnCreateContextMenuListener((menu, v, menuInfo) -> { getMenuInflater().inflate(R.menu.upload_image_menu, menu); int itemCount = menu.size(); for(int i = 0; i < itemCount; i++) { menu.getItem(i).setOnMenuItemClickListener(addPhotosBtnMenuItemClickListener); } }); 

Puesto que en este momento tiene acceso a la vista para la que está creando el menú contextual, puede vincular firmemente al oyente con esa vista.

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.