2009-11-10 9 views
174

J'ai un ListView où chaque élément de la liste contient un TextView et deux boutons différents. Quelque chose comme ceci:Android: éléments ListView avec plusieurs boutons cliquables

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

Donc ma question est, comment puis-je mettre un onClickListener pour ces deux boutons avec les paramètres suivants:

  • int button (qui touche de l'élément a été cliqué)
  • int position (qui est l'élément dans la liste sur laquelle le bouton clic passé)

Mise à jour: J'ai trouvé une solution telle que décrite 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'élément de la liste entière et à partir de là va directement à l'élément de la liste suivante en ignorant les boutons, même si j'ai réglé .setFocusable(true) et setClickable(true) pour les boutons dans getView().

J'ai aussi ajouté ce code à mon adaptateur liste personnalisée:

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

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

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

Quelqu'un a une idée?

+0

Sont-ils encore nécessaires? –

+0

Si vous regardez le code BaseAdapter, vous verrez que areAllItemsEnabled() et isEnabled() sont juste codés en dur à true, ce qui en fait des espaces réservés simples sans aucune logique. –

+0

Et si je veux utiliser un SimpleCursorAdapter? Dois-je faire un adaptateur personnalisé étend simplecursoradapter? – oratis

Répondre

146

La solution à cela est réellement plus facile que je pensais. Vous pouvez simplement ajouter 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 doit être ajouté avec myButton.setTag() dans le getView() et sont accessibles dans le onClickListener via view.getTag()

J'ai posté une solution détaillée sur my blog comme un tutoriel.

+10

"mon blog" url ne fonctionne pas ... – vnshetty

+2

Correction. Merci d'avoir signalé :-) – znq

+0

comment exactement avez-vous obtenu le curItem.url de la requête, seriez-vous plus précis? – oratis

9

Probablement que vous avez trouvé comment le faire, mais vous pouvez appeler

ListView.setItemsCanFocus(true) 

et maintenant vos boutons attraper se concentrer

+0

Merci l'homme cela fonctionne ... a sauvé mon temps. –

60
Ce

est en quelque sorte la réponse d'un appendice @ znq ...

Il existe de nombreux cas où vous souhaitez connaître la position de ligne d'un élément cliqué ET vous voulez savoir quelle vue de la ligne a été sélectionnée. Cela va être beaucoup plus important dans les interfaces utilisateur de 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); 
     } 
    }; 
} 
+6

ou vous pouvez également utiliser quelque chose comme ceci ListView mListView = (ListView) v.getParent(). GetParent(); – max4ever

+1

Comment puis-je obtenir la position si j'utilise l'adaptateur dans une classe séparée. J'ai simplement utilisé la position dans OnClickListener, quelque chose comme ça like_c.get (position). Il suggère de faire la position à final dans la méthode getView de l'adaptateur. Si je fais ce changement, la position que je reçois est la même pour tous les éléments de la lisview. Pourriez-vous me suggérer comment résoudre ceci? – Manikandan

+0

Cest parce que lorsque vous utilisez le paramètre position de la méthode getView, il vous donne la position de l'élément de la liste qui est le plus récemment créé, mais pas celui que vous avez cliqué –

22

Pour les futurs lecteurs:

Pour sélectionner manuellement les boutons avec l'utilisation de boule de commande:

myListView.setItemsCanFocus(true); 

Et pour désactiver la se concentrer sur l'ensemble des éléments de la 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 aussi alows focaliser un clic à l'aide du clavier

+2

Seul celui-ci m'a aidé! Merci beaucoup! – Onur

+0

Merci, j'ai essayé les autres réponses et ni travailler pour moi –

+0

Qu'en est-il un ExpandableListView, j'ai plusieurs vues dans l'élément, je veux juste que les vues dans l'enfant cliquable, merci. – twlkyao

5

Je ne suis pas sûr de la meilleure façon, mais fonctionne très 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; 
} 

} 
-4

est pas la solution de plate-forme pour cette mise en œuvre d'utiliser un menu contextuel qui apparaît sur une presse longue?

L'auteur de la question est-il au courant des menus contextuels? Empiler des boutons dans une liste a des implications sur les performances, encombrera votre interface utilisateur et enfreindra la conception d'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/

+0

Et la raison de la downvote est? – Gusdor

12

Je n'ai pas beaucoup d'expérience que les utilisateurs ci-dessus mais je fait face à ce même problème et je résolu ce problème avec 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" 
     /> 

btnRemoveClick Cliquez événement

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

} 
+0

solution intéressante – sherpya

2

I Sachez qu'il est tard, mais cela peut aider, ceci est un exemple de comment j'écris classe adaptateur personnalisé pour les 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; 
    } 
} 
Questions connexes