¿Cómo agrego un OnClickListener a un botón dentro de un adaptador ListView?

Tengo una vista de lista que contiene la lista de todos mis usuarios. Cada elemento de la lista es un diseño que tiene un botón para mostrar un AlertDialog para cambiar el valor de la etiqueta del botón. ¿Cómo puedo agregar dinámicamente un evento de clic a ese botón generado por el adaptador de vista de lista?

Este es mi adaptador:

public class PerfilAdapter extends BaseAdapter { Context mContext; LayoutInflater mLayoutInflater; List listaPerfiles = new ArrayList(); public Settings01 set=new Settings01(); public PerfilAdapter(Context context,List lista) { mContext = context; mLayoutInflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); listaPerfiles=lista; } @Override public int getCount() { // TODO Auto-generated method stub return listaPerfiles.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return listaPerfiles.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { RelativeLayout itemView; if (convertView == null) { itemView = (RelativeLayout) mLayoutInflater.inflate( R.layout.item_perfil, parent, false); } else { itemView = (RelativeLayout) convertView; } // obtengo los valores de la vista Button moneda = (Button) itemView.findViewById(R.id.Moneda); TextView titulo = (TextView) itemView.findViewById(R.id.Titulo); TextView nombredesc = (TextView) itemView.findViewById(R.id.txtNombre); TextView descripcion = (TextView) itemView.findViewById(R.id.txtDescripcion); String nombreM = Metodos.monedas[listaPerfiles.get(position).getPerfil_tipoMoneda()]; moneda.setText(nombreM); titulo.setText(listaPerfiles.get(position).getPerfil_nombre()); nombredesc.setText(listaPerfiles.get(position).getPerfil_nombreSec()); descripcion.setText(listaPerfiles.get(position).getPerfil_texto()); return itemView; } // metodo parahacer la vista de la celda public void actualizaDatosLista(List listaPerfilesM) { for(int i=0;i<listaPerfilesM.size();i++){ Log.d("ITEM "+i,listaPerfilesM.get(i).getPerfil_nombreSec()); } listaPerfiles = listaPerfilesM; notifyDataSetChanged(); }} 

y esta es mi Actividad:

 public class Settings01 extends Activity implements OnClickListener { private List lst; private PerfilDAO perfildao; private PerfilAdapter perfiladapter; private ListView lstPerfiles; public void changeMoneda(final int position) { int x = 0; AlertDialog.Builder builder = new AlertDialog.Builder(Settings01.this); builder.setTitle("Seleccione Tipo de Distribuidor"); builder.setItems(R.array.moneda, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { lst.get(position).setPerfil_tipoMoneda(item); perfiladapter = new PerfilAdapter(getApplicationContext(), lst); lstPerfiles.setAdapter(perfiladapter); dialog.dismiss(); } }); builder.create(); builder.show(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.settings01); lstPerfiles = (ListView) findViewById(R.id.lstSettings); perfildao = new PerfilDAOImplDB(Settings01.this); lst = new ArrayList(); lst = perfildao.getAll(); perfiladapter = new PerfilAdapter(getApplicationContext(), lst); Log.d("Info", "En Settings"); lstPerfiles.setAdapter(perfiladapter); } @Override public void onClick(View v) { Log.d("Info", "derp" + v.getId()); }} 

Este es el diseño que mi adaptador está usando actualmente:

     

Puede hacerlo en el método getView() de su adaptador. Para eso, necesitará usar un adaptador personalizado (si todavía no lo hace). Será mejor si puede mostrar las partes relevantes de su código.

EDIT: el diálogo se mostrará con tu actividad. Entonces puede crear una interfaz para escuchar este evento de clic de botón.

 public interface BtnClickListener { public abstract void onBtnClick(int position); } 

Deje que su adaptador personalizado lo reciba como entrada.

 private BtnClickListener mClickListener = null; public PerfilAdapter(Context context, List lista, BtnClickListener listener) { mContext = context; mLayoutInflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); listaPerfiles=lista; mClickListener = listener; } 

Ahora puede simplemente configurar el onClickListener normal en getView() como se muestra a continuación

 Button moneda = (Button) itemView.findViewById(R.id.Moneda); moneda.setTag(position); //For passing the list item index moneda.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if(mClickListener != null) mClickListener.onBtnClick((Integer) v.getTag()); } }); 

Deje que su actividad pase el BtnClickListener requerido como parte de la creación del adaptador.

 perfiladapter = new PerfilAdapter(getApplicationContext(), lst, new BtnClickListener() { @Override public void onBtnClick(int position) { // TODO Auto-generated method stub // Call your function which creates and shows the dialog here changeMoneda(position); } }); 

Asumiendo que lst.get(position).setPerfil_tipoMoneda(item); cambia el texto que se usará como texto de botón correctamente, simplemente debe llamar a perfiladapter.notifyDataSetChanged() en el onClick de su dialog (Actualmente está creando el adaptador de nuevo, que no es necesario).

 public void onClick(DialogInterface dialog, int item) { lst.get(position).setPerfil_tipoMoneda(item); perfiladapter.notifyDataSetChanged(); dialog.dismiss(); } 

Espero que funcione como lo esperabas.

En mi caso, tuve que agregar este atributo en ListView:

  

Y en el adaptador simplemente agregue el oyente clic en la vista del botón.

 wrapper.getButtonHi().setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub DebugUtils.logDebug("Clickeado :: "+ mContact.getUserId()); } }); 

Es importante establecer las variables finales:

 public View getRowView(final int position, View convertView, ViewGroup parent) { final BrowseContactItemWrapper wrapper; final UserModel mContact = lstContact.get(position); ..... } 

Solo una pequeña modificación para refrescar el renderizador desde afuera.

 final FinalMenuListAdapter adapter = this; viewHolder.deleteItem.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(mClickListener != null) mClickListener.onBtnClick((MenuItemObject)v.getTag(),adapter); } }); final MenuItemObject menuItemObject = getItem(position); viewHolder.deleteItem.setTag(menuItemObject);