2009-11-10 34 views
174

Tengo un ListView donde cada elemento de la lista contiene un TextView y dos botones diferentes. Algo como esto:Android: elementos ListView con múltiples botones en los que se puede hacer clic

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

Con este código puedo crear una OnItemClickListener para todo el material:

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 todo el elemento se pueda hacer clic, pero sólo los dos botones de cada elemento de lista.

Así que mi pregunta es, ¿Cómo se implementa un OnClickListener para estos dos botones con los siguientes parámetros:

  • int button (el cual ha hecho click en el botón del elemento)
  • int position (que es el elemento en la lista en la que se produjo el clic de 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 he añadido el código a mi adaptador lista personalizada:

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

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

Esto hace que ningún elemento de la lista es seleccionable para nada más. Pero no ayudó a hacer los botones anidados seleccionables.

¿Alguien una idea?

+0

¿Todavía se necesitan? –

+0

Si observa el código BaseAdapter, verá que areAllItemsEnabled() e isEnabled() están codificados como verdaderos, lo que los convierte en simples marcadores de posición sin ninguna lógica. –

+0

¿Qué pasa si quiero usar un SimpleCursorAdapter? ¿Tengo que hacer un adaptador personalizado para extender el simplecursoradapter? – oratis

Respuesta

146

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

cualquier dato asociado con el botón tiene que ser añadido con myButton.setTag() en el getView() y se puede acceder en el OnClickListener través de view.getTag()

he publicado una solución detallada sobre my blog como un tutorial.

+10

URL de "mi blog" no funciona ... – vnshetty

+2

Solucionado. Gracias por informarnos :-) – znq

+0

¿Cuán exactamente obtuviste curItem.url de la consulta, serías más específico? – oratis

9

Probablemente usted ha encontrado cómo hacerlo, pero se puede llamar

ListView.setItemsCanFocus(true) 

y ahora sus botones se pondrá al día se centran

+0

Gracias, hombre, funciona ... me salvó el tiempo. –

60

Esta es una especie de respuesta de un apéndice @ ZNQ ...

Hay muchos casos en los que desea conocer la posición de fila de un elemento seleccionado y desea saber qué vista de la fila se ha tocado. Esto va a ser mucho más importante en las UI de tableta.

Usted puede hacer esto 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); 
     } 
    }; 
} 
+6

o también puede usar algo como esto ListView mListView = (ListView) v.getParent(). GetParent(); – max4ever

+1

¿Cómo puedo obtener la posición si uso el adaptador en una clase separada? Simplemente usé la posición dentro de OnClickListener, algo así como like_c.get (posición). Sugiere que la posición sea definitiva en el método getView del adaptador. Si hago ese cambio, la posición que obtengo es la misma para todos los artículos en el lisview. ¿Podrías sugerirme cómo resolver esto? – Manikandan

+0

Eso es porque cuando usa el parámetro de posición del método getView le da la posición del elemento de la lista que se creó más recientemente pero no el que hizo clic en –

22

Para los futuros lectores:

para seleccionar manualmente los botones con el uso trackball:

myListView.setItemsCanFocus(true); 

Y para desactivar la centrarse en los elementos de la lista completa:

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

Funciona bien para mí, puedo hacer clic en los botones con pantalla táctil y también monoclonales permite enfocar un clic con el teclado

+2

¡Solo esta me ha ayudado! ¡Muchas gracias! – Onur

+0

Gracias, probé las otras respuestas y ni siquiera funcionó para mí –

+0

¿Qué tal un ExpandableListView, tengo varias vistas en el elemento, solo quiero las vistas en las que se puede hacer clic, gracias. – twlkyao

5

No estoy seguro acerca de la mejor manera, pero trabaja muy 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<Telefone> { 

private TelefoneArrayAdapter telefoneArrayAdapter = null; 
private Context context; 
private EditText tipoEditText = null; 
private EditText telefoneEditText = null; 
private ImageView deleteImageView = null; 

public TelefoneArrayAdapter(Context context, List<Telefone> 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; 
} 

} 
-4

no es la solución de plataforma para esta aplicación para utilizar un menú contextual que se muestra en una pulsación larga?

¿El autor de la pregunta conoce los menús contextuales? El apilamiento 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/

+0

¿Y el motivo del voto a favor es? – Gusdor

12

no tengo mucha experiencia de los usuarios anteriores, pero me enfrenté a este mismo tema y he resuelto esto con más adelante Solución

<Button 
     android:id="@+id/btnRemove" 
     android:layout_width="0dp" 
     android:layout_height="wrap_content" 
     android:layout_toRightOf="@+id/btnEdit" 
     android:layout_weight="1" 
     android:background="@drawable/btn" 
     android:text="@string/remove" 
     android:onClick="btnRemoveClick" 
     /> 

btnRemoveClick evento Click

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

} 
+0

solución interesante – sherpya

2

I Saber que es tarde pero esto puede ayudar, este es un ejemplo de cómo escribo la clase de adaptador personalizado 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; 
    } 
} 
Cuestiones relacionadas