¿Cómo manejar el botón OnClick del evento de tarjeta en GridView? Mejores prácticas

Estoy tratando de encontrar la mejor solución para manejar el evento OnClick , que se genera mediante el botón de mi tarjeta (ver la imagen abajo) dentro de GridView .

Mi tarjeta y el botón en él

Así como usted puede ver, tengo apenas un GridView normal con las células hechas de mi tarjeta de encargo.

Acabo de inicializar GridView y su adaptador:

 mGrid = (GridView) findViewById(R.id.grid); mAdapter = new ImageTopicsAdapter(..blah blah blah..); mGrid.setAdapter(mAdapter); 

Como probablemente sabes, puedo manejar fácilmente eventos OnClick generados por GridView . Pero funcionará sólo si hago clic en la propia tarjeta:

 mGrid.setOnItemClickListener(..blah blah blah..); 

Quiero construir algo similar a esto (vea el código abajo), así que puedo fácilmente "implementar" mi Activity para manejar el botón de mi tarjeta OnClick event:

 mGrid.setOnItemButtonClickListener(..blah blah blah..); 

¿Cuál es la mejor manera (limpia \ fácil \ elegante) de hacer esto?

Cualquier ayuda es realmente apreciada. Alex. PS Lo siento por mi inglés 🙂

3 Solutions collect form web for “¿Cómo manejar el botón OnClick del evento de tarjeta en GridView? Mejores prácticas”

Dado que desea enviar a su actividad, recomendaría exponer un método en la actividad y llamar directamente desde su oyente de clics. El más corto (y más limpio desde mi perspectiva):

  • En su adaptador, diga ArrayAdapter

    • Define para escuchar clics (para evitar multitud de instancias de escucha anónimas)
    • Envíe una llamada directamente a su actividad (ya que cada contexto de vista es una actividad)
    • context anterior puede ser tratado como su ApplicationActivity sólo si no manualmente proporcionar algún otro contexto, por ejemplo, el contexto de la aplicación

       private final MyAdapter extends ArrayAdapter implements View.OnClickListener { @Override public View getView(int position, View convertView, ViewGroup parent) { // inflate your card then get a reference to your button View card = ....; card.findViewById(R.id.YOUR_BUTTON_ID).setOnClickListener(this); return card; } @Override public void onClick(View view) { ApplicationActivity activity = (ApplicationActivity) view.getContext(); if (activity != null && !activity.isFinishing()) { applicationActivity.onCardButtonClick(); } } } // in your ApplicationActivity public final class ApplicationActivity extends Activity { ... public void onCardButtonClick() { // deal with your click } } 

Hay otras opciones de textbook (establecer un oyente o actividad en su creación de vista y así sucesivamente), pero los evito ya que no solucionan absolutamente nada.

Sólo añadir más polvo en su código.

Cualquier contexto de View definido correctamente apunta a la actividad (ya que es un contexto también) que contiene toda la estructura de vista. De esta manera puede acceder a su actividad rápida y relativamente fácil.

El bus de eventos BTW no es una buena opción, ya que los buses de eventos son ideales para las relaciones uno a muchos (un despachador, muchos oyentes), pero agregan más complejidad cuando se usan intensivamente para llamadas uno a uno (despachador-oyente)

Adición para el comentario

Usted puede ajustar un poco el código y en lugar de usar el adaptador, puede enviar directamente desde su celular. En otras palabras, en lugar de usar el adaptador como un delegado, crear un oyente anónimo y luego llegar y llamar a la actividad directamente desde el botón de la tarjeta de clic:

 public final MyAdapter extends ArrayAdapter { @Override public View getView(int position, View convertView, ViewGroup parent) { // inflate your card then get a reference to your button View card = ....; card.findViewById(R.id.YOUR_BUTTON_ID).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ApplicationActivity activity = (ApplicationActivity) view.getContext(); if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { applicationActivity.onCardButtonClick(); } } }); return card; } } 

Adición para el comentario – Vista Compuesta

Para encapsular toda la lógica de la celda, puede crear una vista personalizada desde cero o utilizar una vista compuesta . El siguiente ejemplo utiliza una vista compuesta:

 public class ApplicationActivity extends Activity { .... public void onCardButtonClick(Cell cell) { // do whatever you want with the model/view } } // ViewModel instances are used in your adapter public final class ViewModel { public final String description; public final String title; public ViewModel(String title, String description) { this.title = title != null ? title.trim() : ""; this.description = description != null ? description.trim() : ""; } } public final class Cell extends LinearLayout { private View button; private ViewModel model; // ViewModel is data model and is the list of items in your adapter public void update(ViewModel model) { this.model = model; // update your card with your model } public ViewModel getModel() { return model; } @Override protected void onAttachedToWindow() { button = findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener { @Override public void onClick(View view) { ApplicationActivity activity = (ApplicationActivity) view.getContext(); if (model != null && activity != null && !activity.isFinishing() && !activity.isDestroyed() { activity.onCardButtonClick(Cell.this); } } }); } } // then your adapter `getView()` needs to inflate/create your compound view and return it public final MyAdapter extends ArrayAdapter { private final List<ViewModel> items; public MyAdapter() { // update your models from outside or create on the fly, etc. this.items = ...; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { // inflate - say it is a layout file 'cell.xml' convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell); } ((Cell) convertView).update(items.get(position)); return convertView; } } 

El adaptador debe manejar esto. Generalmente su adaptador debe tener el método como setOnOptionsClickListener (OnOptionsClickListener listener) suponiendo que estamos hablando de botón de puntos suspensivos.

Así que en tu Actividad / Fragmento usas el siguiente código

 public interface OnOptionsClickListener { void onOptionsClicked(View view, PictureItem item); } mAdapter= new MyGridAdapter(); mAdapter.setOnOptionsClickListener(new OnOptionsClickListener() { public void onClick(View view, PictureItem item) { //process click } }); 

Y después del adaptador

 public void setOnOptionsClickListener(OnOptionsClickListener l) { mOnOptionsClickListener = l; } findViewById(R.id.btn_options).setOnClickListener(new OnClickListener(){ public void OnClick(View view) { mOnOptionsClickListener.onOptionsClicked(view, currentPictureItem); } }); 

Note por favor. currentPictureItem declarar la interfaz sólo si necesita tener parámetros adicionales en el método OnClick() (por ejemplo, currentPictureItem para obtener la URL de la imagen o el ID del elemento). De lo contrario, puede utilizar sólo OnClickListener.

Editar Así que aquí está la explicación. Adapter sirve como un proveedor de vista para su GridView . Crea vistas y lo configura estado básico. Es por eso que todos los oyentes de clics deben configurarse en Adapter durante la inicialización de las vistas. Por otra parte, no queremos tener una Activity desordenada con el Adapter anidado, pero queremos tener el adaptador como una clase separada. Esta es la razón por la que normalmente necesitará crear una interfaz adicional para tener acceso al objeto currentItem para extraer datos.

Parece que nadie sabe cómo hacer esto. Así que he encontrado la solución con la ayuda de @Dimitar G. y @ Konstantin Kiriushyn. Gracias, muchachos.

1) Voy a crear mi propio CardView personalizado utilizando el sistema de vista compuesta, que será bastante simple: LinearLayout + ImageView + TextView + Button .

 public class TopicCardView extends LinearLayout { private ImageView mImage; private Button mButtonMenu; private TextView mTitle; public TopicCardView (Context context) { initializeViews(context); } private void initializeViews(Context context) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.topic_card_view, this); } private void setTitle(...) { ... } private void setImage(...) { ... } private void setMenuClickListener(...) { ... } // and so on... } 

2) Entonces crearé el método llamado createListOfGridCardsFromDB(...) en Activity\Fragment . CardView la lista ( LinkedList ) de mis CardView personalizados (y también fijará los títulos \ las imágenes y los oyentes a CardView s).

3) Y luego CardView esta LinkedList generada de mi CardView s a GridViewAdapter .

Este sistema hace capaz de utilizar sólo un adaptador para todas mis redes de tarjetas en la aplicación. También hace capaz de no hacer nada con los clics, las interfaces, los oyentes y cosas en el adaptador .

  • Evento de clic transferido a la siguiente Actividad iniciada
  • ¿Por qué no AsyncTasks siempre funcionan dentro de un onClickListener?
  • Android: OnClick para el encabezado del cajón de navegación no funciona
  • Establecer determinado elemento en la vista de cuadrícula que no se puede hacer clic
  • OnClick PendingIntent en widget a veces no funciona
  • Bloqueo de onClick de Android enFling
  • ¿Cómo puedo detectar un clic en el título de ActionBar?
  • Android Múltiples secuencias de clics en textview
  • distinguir un golpe y hacer clic en android (pasar el evento a otra vista si es un golpe)
  • Cerrar Spinner en clic fuera de Spinner
  • Android ClickableSpan obtener texto onClick ()
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.