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 ceci:

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'ensemble de l'article:

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'article entier soit cliquable, mais seulement les deux boutons de chaque élément de liste.

alors ma question Est, Comment puis-je implémenter un onClickListener pour ces deux boutons avec les paramètres 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 bouton cliquer s'est produit)

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

j'ai aussi ajouté ce code à mon adaptateur de liste personnalisé:

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

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

cela provoque qu'aucun élément de liste n'est plus sélectionnable du tout. Mais ça n'a pas aidé à rendre les boutons emboîtés sélectionnables.

une idée?

178
demandé sur znq 2009-11-10 19:17:31

8 réponses

la solution à cela est en fait plus facile que je pensais. Vous pouvez simplement ajouter dans votre adaptateur personnalisé getView() méthode un setOnClickListener () pour les boutons que vous utilisez.

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

j'ai posté une solution détaillée sur mon blog comme un tutoriel.

150
répondu znq 2014-09-14 01:44:34

c'est une sorte d'appendice de la réponse de @znq...

il y a de nombreux cas où vous voulez connaître la position de la rangée pour un élément cliqué et vous voulez savoir quelle vue dans la rangée a été tappée. Cela va être beaucoup plus important dans les tablettes UIs.

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);
        }
    };
}
62
répondu greg7gkb 2012-09-18 00:24:38

pour les futurs lecteurs:

pour sélectionner manuellement les boutons avec la trackball utiliser:

myListView.setItemsCanFocus(true);

Et de désactiver l'accent sur l'ensemble des éléments de liste:

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

il fonctionne très bien pour moi, je peux cliquer sur les boutons Avec Écran tactile et permet également focus un clic en utilisant le clavier

22
répondu Fabricio PH 2012-03-23 14:39:03

Je n'ai pas beaucoup d'expérience que les utilisateurs ci-dessus, mais j'ai fait face à ce même problème et je L'ai résolu avec la Solution ci-dessous

<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 Cliquez sur l'événement

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

}
12
répondu Bhavin Chauhan 2015-06-01 00:41:31

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

ListView.setItemsCanFocus(true)

et maintenant vos boutons vont se focaliser

9
répondu Rafal 2014-02-03 01:09:25

Je ne suis pas sûr d'être le meilleur moyen, mais fonctionne bien et tous les codes restent 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<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;
}

}
5
répondu mFontolan 2015-02-19 11:35:35

je sais qu'il est tard, mais cela peut aider, c'est un exemple de la façon dont j'écris la classe adaptateur personnalisé 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;
    }
}
2
répondu Redman 2016-12-14 09:20:38

N'est-ce pas la solution plate-forme pour cette implémentation d'utiliser un menu contextuel qui s'affiche sur une longue presse?

L'auteur de la question connaît-il les menus contextuels? Empiler des boutons dans un listview a des implications sur les performances, encombrera votre interface utilisateur et violera la conception D'interface utilisateur recommandée pour la plate-forme.

sur le côté; les menus contextuels - par nature n'ayant pas 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/

-4
répondu Gusdor 2015-02-19 11:38:59