Android: elementos ListView con múltiples botones clicables

Tengo un ListView donde cada elemento de la lista contiene un TextView y dos botones diferentes. Algo como esto:

 ListView -------------------- [Text] [Button 1][Button 2] -------------------- [Text] [Button 1][Button 2] -------------------- ... (and so on) ... 

Con este código puedo crear un OnItemClickListener para todo el artículo:

 listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView list, View view, int position, long id) { Log.i(TAG, "onListItemClick: " + position); } } }); 

Sin embargo, no quiero que se pueda hacer clic en todo el elemento, sino solo en los dos botones de cada elemento de la lista.

Entonces mi pregunta es, ¿cómo implemento un OnClickListener para estos dos botones con los siguientes parámetros:

  • int button (en qué botón del elemento se ha hecho clic)
  • int position (que es el elemento de la lista en la que se produjo el clic del botón)

Actualización: Encontré una solución como se describe en mi respuesta a continuación. Ahora puedo hacer clic / tocar el botón a través de la pantalla táctil. Sin embargo, no puedo seleccionarlo manualmente con la bola de seguimiento. Siempre selecciona todo el elemento de la lista y desde allí va directamente al siguiente elemento de la lista ignorando los botones, aunque configuré .setFocusable(true) y setClickable(true) para los botones en getView() .

También agregué este código a mi adaptador de lista personalizado:

 @Override public boolean areAllItemsEnabled() { return false; } @Override public boolean isEnabled(int position) { return false; } 

Esto hace que ningún elemento de la lista sea seleccionable en absoluto. Pero no ayudó a hacer los botones nesteds seleccionables.

Alguien una idea?

    La solución a esto es realmente más fácil de lo que pensaba. Simplemente puede agregar el método getView () de un adaptador personalizado setOnClickListener () para los botones que está usando.

    Todos los datos asociados con el botón se deben agregar con myButton.setTag() en getView() y se puede acceder en onClickListener a través de view.getTag()

    Publiqué una solución detallada en mi blog como tutorial.

    Esta es una especie de respuesta de appendage @ znq …

    Hay muchos casos en los que desea saber la posición de la fila para un elemento en el que se hace clic Y desea saber qué vista de la fila se tocó. Esto va a ser mucho más importante en las UI de tableta.

    Puede hacerlo con el siguiente adaptador personalizado:

     private static class CustomCursorAdapter extends CursorAdapter { protected ListView mListView; protected static class RowViewHolder { public TextView mTitle; public TextView mText; } public CustomCursorAdapter(Activity activity) { super(); mListView = activity.getListView(); } @Override public void bindView(View view, Context context, Cursor cursor) { // do what you need to do } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { View view = View.inflate(context, R.layout.row_layout, null); RowViewHolder holder = new RowViewHolder(); holder.mTitle = (TextView) view.findViewById(R.id.Title); holder.mText = (TextView) view.findViewById(R.id.Text); holder.mTitle.setOnClickListener(mOnTitleClickListener); holder.mText.setOnClickListener(mOnTextClickListener); view.setTag(holder); return view; } private OnClickListener mOnTitleClickListener = new OnClickListener() { @Override public void onClick(View v) { final int position = mListView.getPositionForView((View) v.getParent()); Log.v(TAG, "Title clicked, row %d", position); } }; private OnClickListener mOnTextClickListener = new OnClickListener() { @Override public void onClick(View v) { final int position = mListView.getPositionForView((View) v.getParent()); Log.v(TAG, "Text clicked, row %d", position); } }; } 

    Para futuros lectores:

    Para seleccionar manualmente los botones con la bola de seguimiento, use:

     myListView.setItemsCanFocus(true); 

    Y para deshabilitar el enfoque en los elementos de la lista completa:

     myListView.setFocusable(false); myListView.setFocusableInTouchMode(false); myListView.setClickable(false); 

    Me funciona bien, puedo hacer clic en los botones con pantalla táctil y también centrar un clic usando el teclado

    No tengo mucha experiencia que los usuarios anteriores, pero me enfrenté a este mismo problema y lo resolví con la siguiente solución

      

    btnRemoveClick Click evento

     public void btnRemoveClick(View v) { final int position = listviewItem.getPositionForView((View) v.getParent()); listItem.remove(position); ItemAdapter.notifyDataSetChanged(); } 

    Probablemente haya encontrado cómo hacerlo, pero puede llamar

     ListView.setItemsCanFocus(true) 

    y ahora tus botones captarán el foco

    No estoy seguro de ser la mejor manera, pero funciona bien y todo el código permanece en su ArrayAdapter.

     package br.com.fontolan.pessoas.arrayadapter; import java.util.List; import android.content.Context; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ImageView; import br.com.fontolan.pessoas.R; import br.com.fontolan.pessoas.model.Telefone; public class TelefoneArrayAdapter extends ArrayAdapter { private TelefoneArrayAdapter telefoneArrayAdapter = null; private Context context; private EditText tipoEditText = null; private EditText telefoneEditText = null; private ImageView deleteImageView = null; public TelefoneArrayAdapter(Context context, List values) { super(context, R.layout.telefone_form, values); this.telefoneArrayAdapter = this; this.context = context; } @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.telefone_form, parent, false); tipoEditText = (EditText) view.findViewById(R.id.telefone_form_tipo); telefoneEditText = (EditText) view.findViewById(R.id.telefone_form_telefone); deleteImageView = (ImageView) view.findViewById(R.id.telefone_form_delete_image); final int i = position; final Telefone telefone = this.getItem(position); tipoEditText.setText(telefone.getTipo()); telefoneEditText.setText(telefone.getTelefone()); TextWatcher tipoTextWatcher = new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { telefoneArrayAdapter.getItem(i).setTipo(s.toString()); telefoneArrayAdapter.getItem(i).setIsDirty(true); } }; TextWatcher telefoneTextWatcher = new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { telefoneArrayAdapter.getItem(i).setTelefone(s.toString()); telefoneArrayAdapter.getItem(i).setIsDirty(true); } }; tipoEditText.addTextChangedListener(tipoTextWatcher); telefoneEditText.addTextChangedListener(telefoneTextWatcher); deleteImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { telefoneArrayAdapter.remove(telefone); } }); return view; } } 

    Sé que es tarde pero esto puede ayudar, este es un ejemplo de cómo escribo una clase de adaptador personalizada para diferentes acciones de clic

      public class CustomAdapter extends BaseAdapter { TextView title; Button button1,button2; public long getItemId(int position) { return position; } public int getCount() { return mAlBasicItemsnav.size(); // size of your list array } public Object getItem(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = getLayoutInflater().inflate(R.layout.listnavsub_layout, null, false); // use sublayout which you want to inflate in your each list item } title = (TextView) convertView.findViewById(R.id.textViewnav); // see you have to find id by using convertView.findViewById title.setText(mAlBasicItemsnav.get(position)); button1=(Button) convertView.findViewById(R.id.button1); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //your click action // if you have different click action at different positions then if(position==0) { //click action of 1st list item on button click } if(position==1) { //click action of 2st list item on button click } }); // similarly for button 2 button2=(Button) convertView.findViewById(R.id.button2); button2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //your click action }); return convertView; } } 

    ¿No es la solución de la plataforma para esta implementación el uso de un menú contextual que se muestra en una pulsación larga?

    ¿Conoce el autor de la pregunta los menús contextuales? El astackmiento de botones en una vista de lista tiene implicaciones de rendimiento, saturará su interfaz de usuario y violará el diseño de interfaz de usuario recomendado para la plataforma.

    En el otro lado; los menús contextuales, por la naturaleza de no tener una representación pasiva, no son obvios para el usuario final. Considera documentar el comportamiento?

    Esta guía debería darle un buen comienzo.

    http://www.mikeplate.com/2010/01/21/show-a-context-menu-for-long-clicks-in-an-android-listview/