web-dev-qa-db-fra.com

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 tout 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 tout l'élément soit cliquable, mais uniquement les deux boutons de chaque élément de la liste.

Ma question est donc la suivante: comment implémenter un onClickListener pour ces deux boutons avec les paramètres suivants:

  • int button (sur quel bouton de l'élément a été cliqué)
  • int position (qui est l'élément de la liste sur lequel le clic de bouton est arrivé)

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 la boule de commande. Il sélectionne toujours l’ensemble de l’élément de la liste et de là, passe directement à l’élément de liste suivant en ignorant les boutons, même si je règle .setFocusable(true) et setClickable(true) pour les boutons de getView().

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

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

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

Cela fait qu'aucun élément de la liste ne peut plus être sélectionné. Mais cela n'a pas aidé à rendre les boutons imbriqués sélectionnables.

Quelqu'un a une idée?

181
znq

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

Toute donnée associée à la touche doit être ajoutée avec myButton.setTag() dans getView() et est accessible dans onClickListener via view.getTag().

J'ai posté une solution détaillée sur mon blog sous forme de tutoriel.

150
znq

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

Dans de nombreux cas, vous souhaitez connaître la position de la ligne pour un élément cliqué ET savoir quelle vue de la ligne a été exploitée. Cela sera beaucoup plus important dans les interfaces utilisateur de la tablette.

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
greg7gkb

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 les boutons avec l’écran tactile et permet également de mettre au point un clic à l’aide du clavier.

22
Fabricio PH

Je n'ai pas beaucoup d'expérience que les utilisateurs précédents, mais j'ai été confronté au même problème et j'ai résolu le problème ci-dessous Solution

<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"
        />

evénement btnRemoveClick Click

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

}
12
Bhavin Chauhan

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

ListView.setItemsCanFocus(true)

et maintenant vos boutons vont attraper le focus

9
Rafal

Je ne suis pas sûr d'être le meilleur moyen, mais cela fonctionne bien et tout le code reste 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
mFontolan

Je sais qu'il est tard mais cela peut aider, voici un exemple d'écriture de classe d'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;
    }
}
3
Manohar Reddy