Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Cómo saber qué vista dentro de un elemento ListView específico al que se hizo clic

Tengo un ListView con mi propio adaptador personalizado derivado de un BaseAdapter . Cada elemento del ListView tiene elementos secundarios como ImageView y TextView .

¿Cómo puedo saber cuál de estos sub-ítems ha hecho clic en el usuario? ¿Es posible adjuntar un oyente en la función getView por ejemplo, o podría ser un problema?

Henrik

Edit: Actualmente tengo un onItemClick en la actividad que contiene ListView . ¿Hay alguna buena manera de saber qué sub ítem en un elemento específico en el ListView que se ha presionado mediante la comprobación de los parámetros en el onItemClick .

 @Override public void onItemClick(AdapterView<?> a, View v, int pos, long id) { . . } 

  • Vista de la lista de android
  • Android Listview - no puede seleccionar varios elementos cuando usa un cursor
  • Test Robolectric ListView no se actualiza después de cambios de valor en el adaptador
  • (Android) listview con varios botones, no se puede hacer clic en el elemento de lista
  • Listview con arraylist, adaptador simple en android
  • ¿Cuál es la diferencia entre argumento "int" y "long" en onItemClick en Android
  • Entradas duplicadas en ListView
  • Separadores ListView con un CursorAdapter
  • 5 Solutions collect form web for “Cómo saber qué vista dentro de un elemento ListView específico al que se hizo clic”

    Puedes hacerlo. Necesita modificar su método getView:

     @Override public View getView(final int position, View row, final ViewGroup parent) { ... YourWrapper wrapper = null; if (row == null) { row = getLayoutInflater().inflate(R.layout.your_row, parent, false); wrapper = new YourWrapper(row); row.setTag(wrapper); } else { wrapper = (YourWrapper) row.getTag(); } wrapper.yourSubView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // do something } ... } 

    Utilicé una idea de la Programación Hobby de Miga .

    La clave es llamar performItemClick () desde el nuevo oyente onClick. Esto pasa el clic a través de la onItemClick () que ya se está utilizando para la lista. Es tan rápido y fácil, siento que estoy engañando.

    Aquí está getView (), desde el adaptador de lista:

     @Override public View getView(final int position, View convertView, final ViewGroup parent) { // Check if an existing view is being reused, otherwise inflate the view if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.one_line, parent, false); } // This chunk added to get textview click to register in Fragment's onItemClick() // Had to make position and parent 'final' in method definition convertView.findViewById(R.id.someName).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ((ListView) parent).performItemClick(v, position, 0); } }); // do stuff... } 

    Y el onItemClick ():

     @Override public void onItemClick(AdapterView adapterView, View view, int position, long id) { long viewId = view.getId(); if (viewId == R.id.someName) { Toast.makeText(getActivity(), "someName item clicked", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(getActivity(), "ListView clicked: " + id, Toast.LENGTH_SHORT).show(); } } 

    ListView recicla los objetos de vista de fila y asigna nuevos datos sobre ellos cuando se llama "getView", por lo que el enfoque a utilizar, es añadir un listener en la función getView. Aquí hay un ejemplo de código de una aplicación que muestra cómo se hace:

     private class DeletePlayerAdapter extends ArrayAdapter<Player> { Context context; int layoutResourceId; ArrayList<Player> data; public DeletePlayerAdapter(Context context, int layout, ArrayList<Player> list) { super(context, layout, list); this.layoutResourceId = layout; this.context = context; this.data = list; } @Override public View getView(final int position, View convertView, ViewGroup parent) { View row = convertView; PlayerHolder holder = null; if (row == null) { LayoutInflater inflater = ((Activity) context) .getLayoutInflater(); row = inflater.inflate(layoutResourceId, parent, false); holder = new PlayerHolder(); holder.player_name = (TextView) row .findViewById(R.id.player_name); holder.player_number = (TextView) row .findViewById(R.id.player_number); holder.seeded_button = (ImageButton) row .findViewById(R.id.delete_toggle); holder.player_name.setTypeface(tf); holder.player_number.setTypeface(tf); row.setTag(holder); players_array.get(position).marked_for_delete = false; } else { Log.d("PLAYER_ADAPTER", "NOT_NULL ROW"); holder = (PlayerHolder) row.getTag(); } holder.seeded_button.setOnClickListener(new OnClickListener() { // // Here is the magic sauce that makes it work. // private int pos = position; public void onClick(View v) { ImageButton b = (ImageButton) v; if (b.isSelected()) { b.setSelected(false); players_array.get(pos).marked_for_delete = false; } else { b.setSelected(true); players_array.get(pos).marked_for_delete = true; } } }); Player p = data.get(position); holder.player_name.setText(p.name); holder.player_number.setText(String.valueOf(position+1)); holder.seeded_button .setSelected(players_array.get(position).marked_for_delete); return row; } } static class PlayerHolder { TextView player_number; TextView player_name; ImageButton seeded_button; } 

    Puesto que sólo tiene un ImageView y un TextView, puede cambiar ImageView a ImageButton. A continuación, puede agregar un oyente en el ImageButton que se llamará si el usuario hace clic en la imagen. Si hace clic en cualquier otro lugar dentro del elemento (incluido el TextView), se llamará onItemclicklistener. Esto es mucho más simple, creo.

    Me ocurrió una solución genérica y reutilizable. En lugar de extender un adaptador de lista concreto y modificar el método getView() , creé una nueva clase implementando la interfaz ListAdapter que ciegamente reenvía casi todo a otro ListAdapter excepto getView() . Se parece a esto:

     public class SubClickableListAdapter implements ListAdapter { public static interface OnSubItemClickListener { public void onSubItemClick(View subView, int position); } private ListAdapter other; private SparseArray<OnSubItemClickListener> onClickListeners; public SubClickableListAdapter(ListAdapter other) { this.other = other; onClickListeners = new SparseArray<OnSubItemClickListener>(); } public void setOnClickListener(int id, OnSubItemClickListener listener) { onClickListeners.put(id, listener); } public void removeOnClickListener(int id) { onClickListeners.remove(id); } @Override public View getView(final int position, View convertView, ViewGroup parent) { View view = other.getView(position, convertView, parent); for(int i = 0; i < onClickListeners.size(); i++) { View subView = view.findViewById(onClickListeners.keyAt(i)); if (subView != null) { final OnSubItemClickListener listener = onClickListeners.valueAt(i); if (listener != null) { subView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { listener.onSubItemClick(v, position); } }); } } } return view; } // other implemented methods } 

    Los otros métodos implementados simplemente se parecen a los siguientes:

     @Override public Object getItem(int position) { return other.getItem(position); } 

    Para usarlo, simplemente ListAdapter suministrando cualquier otro ListAdapter (ya sea ArrayAdapter o SimpleCursorAdapter o cualquier otra cosa). A continuación, llame a setOnClickListener() para cada vista donde desee escuchar en los clics, dando su id en el parámetro id y su oyente en el parámetro listener . Para obtener el id de fila para la fila que se ha hecho clic, llame al getItemIdAtPosition(position) de su ListView (que tiene que obtener de otra manera, porque no se da como parámetro a su devolución de llamada, pero que no debe ser un gran Problema en la mayoría de los casos).

    La ventaja de esta solución es que se puede utilizar con cualquier ListAdapter . Así que si su aplicación tiene varios ListView , cada uno usando diferentes vistas subyacentes, o incluso adaptadores diferentes, no tiene que crear una nueva clase de adaptador para cada uno.

    El problema con esto es lo mismo que con todas las otras soluciones: el OnItemClick() de ListView no se llamará si hace clic en una vista para la que registró un oyente. Para las vistas que usted no registró un oyente, esta llamada de retorno será llamada sin embargo. Por ejemplo, si tiene una actividad para el elemento de lista que contiene dos campos de texto y un botón y registra un oyente para el botón, al hacer clic en el botón no llamará a OnItemClick() del ListView , En su lugar. Al hacer clic en cualquier otro lugar llama OnItemClick() .

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