Android: éléments ListView avec plusieurs boutons cliquables

J’ai un ListView où chaque élément de la liste contient un TextView et deux boutons différents. Quelque chose comme ça:

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

Avec ce code, je peux créer un OnItemClickListener pour l’élément entier:

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

Cependant, je ne veux pas que l’élément soit cliquable, mais seulement les deux boutons de chaque élément de la liste.

Donc, ma question est, comment puis-je implémenter un onClickListener pour ces deux boutons avec les parameters suivants:

  • int button (quel bouton de l’élément a été cliqué)
  • int position (qui est l’élément de la liste sur lequel le clic du bouton s’est produit)

Mise à jour: J’ai trouvé une solution comme décrit dans ma réponse ci-dessous. Maintenant, je peux cliquer / toucher le bouton via l’écran tactile. Cependant, je ne peux pas le sélectionner manuellement avec le trackball. Il sélectionne toujours l’intégralité de l’élément de liste et de là va directement à l’élément de liste suivant en ignorant les boutons, même si je .setFocusable(true) et setClickable(true) pour les boutons dans getView() .

J’ai également ajouté ce code à mon adaptateur de liste personnalisée:

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

Cela fait qu’aucun élément de la liste n’est plus sélectionnable. Mais cela n’a pas aidé à rendre les boutons nesteds sélectionnables.

Quelqu’un a une idée?

La solution à ce problème est en fait plus facile que je le pensais. Vous pouvez simplement append dans la méthode getView () de votre adaptateur personnalisé un setOnClickListener () pour les boutons que vous utilisez.

Toutes les données associées au bouton doivent être ajoutées avec myButton.setTag() dans getView() et accessibles dans onClickListener via view.getTag()

J’ai posté une solution détaillée sur mon blog en tant que tutoriel.

Ceci est en quelque sorte la réponse d’un appendice @ znq …

Il y a de nombreux cas où vous voulez connaître la position de la ligne pour un élément cliqué ET vous voulez savoir quelle vue de la ligne a été tapée. Cela va être beaucoup plus important dans les interfaces utilisateur des tablettes.

Vous pouvez le faire avec l’adaptateur personnalisé suivant:

 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); } }; } 

Pour les futurs lecteurs:

Pour sélectionner manuellement les boutons avec la boule de commande, utilisez:

 myListView.setItemsCanFocus(true); 

Et pour désactiver le focus sur tous les éléments de la liste:

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

Cela fonctionne très bien pour moi, je peux cliquer sur des boutons avec écran tactile et permet aussi de faire un clic en utilisant le clavier

Je n’ai pas beaucoup d’expérience que les utilisateurs ci-dessus, mais j’ai rencontré le même problème et j’ai résolu ce problème avec la solution ci-dessous.

  

événement btnRemoveClick Click

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

Vous avez probablement trouvé comment le faire, mais vous pouvez appeler

 ListView.setItemsCanFocus(true) 

et maintenant vos boutons vont se concentrer

Je ne suis pas sûr d’être le meilleur moyen, mais fonctionne bien et tout le code rest dans votre 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.toSsortingng()); 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.toSsortingng()); 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; } } 

Je sais qu’il est tard mais cela peut aider, voici un exemple de la façon dont j’écris une classe d’adaptateur personnalisée pour différentes actions 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; } } 

La solution de plate-forme pour cette implémentation ne doit-elle pas utiliser un menu contextuel qui s’affiche sur un long appui?

L’auteur de la question est-il au courant des menus contextuels? L’empilage des boutons dans une vue de liste a des conséquences sur les performances, encombrera votre interface utilisateur et violera la conception de l’interface utilisateur recommandée pour la plate-forme.

Sur le revers les menus contextuels – par nature de ne pas avoir de représentation passive – ne sont pas évidents pour l’utilisateur final. Envisager de documenter le comportement?

Ce guide devrait vous donner un bon départ.

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