Disparar un PopupMenu con botones dentro de un elemento ListView

Tipos de menú

Permítanme comenzar destacando la distinción entre menús contextuales y menús emergentes (tomados de aquí ):

Como orientación, los documentos distinguen entre sus usos: – PopupMenu: "Proporcionar un menú de estilo de desbordamiento para acciones que se relacionan con contenido específico (como los encabezados de correo electrónico de Gmail …" – ContextualMenu: "Para acciones que afectan a contenido seleccionado … "

Estoy después de la apariencia visual y la interacción de la PopupMenu .

Mi configuración (y el objetivo)

Tengo un ListView donde cada artículo tiene un botón a la derecha.

-------------------- | Item 1 [ ]| -------------------- -------------------- | Item ... [ ]| -------------------- -------------------- | Item n [ ]| -------------------- 

Mientras conserva el onItemClick para cada ListItem, me gustaría aprovechar el botón para activar un PopupMenu .

Las acciones en el PopupMenu se enumeran en my_menu.xml , por lo que la única diferencia entre cada instancia del menú es el elemento para el que se hizo clic.

Lo que he intentado

He intentado sobreescribir getView() en mi ListAdapter para agregar un OnClickListener para cada botón, según esta publicación . El resultado fue inconsistente; No todos los clics se registraron (quizás debido al reciclaje – no he probado esta solución todavía) pero en general el enfoque parecía squiffy, teniendo en cuenta la facilidad de especificar un menú contextual para un listview.

También he intentado agregar un menú contextual, que era absolutamente fácil, excepto que es accionado solamente cuando el artículo de la lista es prensado.

¿Es el método getView() el camino a seguir o hay algo más fácil?

En mi listview, tengo un mini botón de desbordamiento para cada elemento, similar a cada pista de la lista de reproducción de Play Music. Muestran un PopupMenu para cada artículo allí, cuando usted chasca encendido el botón del desbordamiento. La prensa larga no hace nada.

Me gustaría que, pero no estoy seguro de cómo? La página de menú sólo explica cómo habilitar un menú emergente para vistas individuales.

registerForContextMenu(ListView lv) es la única cosa que he visto que puedo aplicar a un ListView entero, pero que parece que sólo funciona en prensas largas de toda la lista. ¿Hay una forma de conectar ese evento a un clic de una vista específica en un elemento de la lista (mientras se mantiene el elemento de lista, haga clic para el resto del elemento de lista)?

He intentado establecer un onClickListener en getView() como se describe aquí, pero se siente squiffy para PopupMenu, y no todos los clics se registraron cada vez (era consistentemente inconsistente).

Actualizar – con getView () reemplazado de nuevo

Cuando creo el StacksCursorAdapter, paso una instancia de StackViewFragment que se almacena como un campo (así que se puede asignar a las vistas como el oyente del tecleo).

ViewHolder es una clase con public final ImageView miniOverflow

StacksCursorAdapter (extends SimpleCursorAdapter):

 @Override public View getView(int position, View convertView, ViewGroup parent) { View row = super.getView(position, convertView, parent); ViewHolder holder = (ViewHolder) row.getTag(); if (holder == null) { holder = new ViewHolder(row); row.setTag(holder); } holder.miniOverflow.setTag(R.id.tag_stack_position, position); holder.miniOverflow.setOnClickListener(listener); return row; } 

StackViewFragment (extends ListFragment, implementa View.OnClickListener):

 @Override public void onClick(View v) { Log.d(TAG, "mini overflow clicked"); Log.d(TAG, "position:::::" + v.getTag(R.id.tag_stack_position)); PopupMenu popup = new PopupMenu(getActivity(), v); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.menu_stackview_listitem, popup.getMenu()); popup.show(); } 

Stack_list_item.xml:

 <?xml version="1.0" encoding="utf-8"?> <!-- a single row item for a Stacks listview --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="48dp" android:descendantFocusability="blocksDescendants" > ... <other views> ... <ImageView android:id="@+id/moreoverflow_btn" android:focusable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:alpha="0.4" android:scaleType="fitCenter" android:src="@drawable/ic_menu_moreoverflow_black" android:layout_alignParentRight="true" /> </RelativeLayout> 

El problema en este cruce es que tengo que hacer clic varias veces de vez en cuando para obtener el clic para registrar (en el botón). Esto es sin desplazamiento, por lo que no está relacionado con ver el reciclaje.

Conclusión (la solución de eskimoapps.com está marcada como correcta)

Así que no hubo ningún problema con los múltiples clics excepto que mi objetivo táctil no estaba en el lugar que esperaba: el recurso de imagen que estaba usando para el mini desbordamiento se pesa a la derecha (de tal manera que los tres puntos están cerca del borde derecho de El objetivo táctil) lo que significa que yo estaba perdiendo la mitad del tiempo (facepalm).

La getView() como he mostrado anteriormente parece funcionar bien, y de hecho, getView() se puede modificar aún más, al establecer OnClickListener sólo si es necesario (pero sin duda, la actualización de la etiqueta debe hacerse para cada vista, no Sólo los recién creados):

 @Override public View getView(int position, View convertView, ViewGroup parent) { View row = super.getView(position, convertView, parent); ViewHolder holder = (ViewHolder) row.getTag(); if (holder == null) { holder = new ViewHolder(row); row.setTag(holder); holder.miniOverflow.setOnClickListener(listener); } holder.miniOverflow.setTag(R.id.tag_stack_position, position); return row; } 

Superar getView es el enfoque correcto, y estás en el camino correcto pensando que reciclar vistas complicará las cosas (si de hecho estás reciclando las vistas).

Puesto que no hay métodos getOnClickListener, sólo tendrás que establecer un nuevo OnClickListener para las vistas recicladas, así como las que no estén infladas (si no quieres crear una vista personalizada que implemente getOnClickListener).

Si quisiera hacer esto hoy, usaría el patrón de HolderView .

El patrón de HolderView requiere una vista / grupo de vista personalizada (una clase que extiende el grupo View / View que es la raíz del diseño de elementos de la lista / cuadrícula, con los 3 constructores de vistas estándar).

La idea general es que el adaptador no es responsable de actualizar el contenido de la vista directamente; En su lugar, le dará a la vista toda la información necesaria para actualizarse:

 @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = createView(parent); } updateView((GalleryItemView) convertView, position); return convertView; } private View createView(ViewGroup parent) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); return inflater.inflate(R.layout.gallery_item_view, null, false); } private void updateView(GalleryItemView view, int position) { GalleryElement item = getItem(position); view.updateWith(position, item, listener); } 

En mi opinión:

 public class GalleryItemView extends ImageView { public GalleryItemView(Context context, AttributeSet attrs) { super(context, attrs); } void updateWith(int position, final GalleryElement item, final GalleryAdapter.GalleryItemListener listener) { if (position % 2 == 0) { setBackgroundColor(getColor(android.R.color.holo_orange_dark)); } else { setBackgroundColor(getColor(android.R.color.holo_orange_light)); } setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { listener.onGalleryItemClicked(item.id); } }); } @ColorInt private int getColor(@ColorRes int colorRes) { return getResources().getColor(colorRes); } } 
  • Modificar el elemento seleccionado en Numberpicker Android
  • Android: agregar elementos a un ListView con TranscriptMode establecido en Normal
  • Cómo inflar RelativeLayout de XML
  • Android: Problemas con ListViews y CheckBoxes
  • Destruir vista (disposición)
  • Android Checkbox listview seleccionar todo (desactivar / activar)
  • Cómo rellenar JSON desde este enlace a Android Listview
  • Cambiar en el adaptador para un ListView
  • OnItemClickListener consume eventos onClickListener
  • Listview no muestra nada y ocultar datos
  • ¿Cómo afectar a elementos fuera de un listview cuando se hace clic en algunos elementos de la vista de lista?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.