Lorsque le défilement personnalisé ListView, la case de changement de la valeur
Ce que j'ai: personnalisé listview avec Textviews et une case à cocher.
Problème: Suppose que mon écran ne peut afficher que 6 éléments de liste à la fois, et les autres sont invisibles.
Donc j'ai vérifié le premier élément de la liste (élément à la position 0). Je défiler vers le bas pour voir tous mes une liste, quand j'ai faites défiler jusqu'au premier élément (élément à la position 0) la case à cocher est cochée correctement. Super! Mais maintenant, il y a de nouveaux éléments thath sont vérifiées, par exemple, l'élément à la position 8 (parce que quand j'ai faites défiler la liste (pour theRycicling) pour devenir le nouvel élément à la position 0..souviens de mon écran ne montre que 7 éléments à la fois). Et c'est vérifié, mais je n'ai jamais vérifié!
Question: Comment je peux éviter ce problème? Je ne veux pas que la case que je n'ai pas cliquez sur modifier leur statut.
Ci-dessous mon adaptateur pour listView avec le getView fonction où j'ai mis en œuvre la setOnCheckedChangeListener:
public class NewQAAdapterSelectFriends extends BaseAdapter {
private LayoutInflater mInflater;
private Person[] data;
public NewQAAdapterSelectFriends(Context context) {
mInflater = LayoutInflater.from(context);
}
public void setData(Person[] data) {
this.data = data;
}
@Override
public int getCount() {
return data.length;
}
@Override
public Object getItem(int item) {
return data[item];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_select_friends, null);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
viewHolder.nameText.setTag(viewHolder.nameText);
viewHolder.nameText.setTag(viewHolder.surnameText);
viewHolder.contactImage.setTag(data[position]);
viewHolder.checkBox.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
Person element = (Person) viewHolder.checkBox.getTag();
if(isChecked){
element.setCheck(buttonView.isChecked());
//data[position].setCheck(true); //this is equivalent to previous line
}
else{
//to-do
}
}
});
viewHolder.checkBox.setTag(data[position]);
} else {
}
ViewHolder holder = (ViewHolder) convertView.getTag();
holder.nameText.setText(data[position].getName());
holder.surnameText.setText(data[position].getSurname());
holder.contactImage.setImageResource(data[position].getPhotoRes());
holder.contactImage.setScaleType(ScaleType.FIT_XY);
holder.checkBox.setChecked(data[position].isCheck());
return convertView;
}
static class ViewHolder {
TextView nameText;
TextView surnameText;
ImageView contactImage;
CheckBox checkBox;
}
}
Merci pour les réponses 🙂
EDIT: Avec la suggestion que j'ai changé mon getView comme ci-dessous:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_select_friends, null);
viewHolder=new ViewHolder();
viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
viewHolder.nameText.setTag(viewHolder.nameText);
viewHolder.nameText.setTag(viewHolder.surnameText);
viewHolder.contactImage.setTag(data[position]);
viewHolder.checkBox.setChecked(data[position].isCheck());
viewHolder.checkBox.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
if(viewHolder.checkBox.isChecked()==true)
data[position].setCheck(true);
else
data[position].setCheck(false);
}
});
}
else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.nameText.setText(data[position].getName());
viewHolder.surnameText.setText(data[position].getSurname());
viewHolder.contactImage.setImageResource(data[position].getPhotoRes());
viewHolder.contactImage.setScaleType(ScaleType.FIT_XY);
viewHolder.checkBox.setChecked(data[position].isCheck());
return convertView;
}
SITUATION APRÈS EDIT: Maintenant, si je coche les points initiaux qui s'affiche sur l'écran et puis je scrool la liste, leur valeur est correctement enregistré. Mais Quand j'ai faites défiler la liste et, par exemple, je veux vérifier que le dernier arbre checkboxs de ma liste puis après j'ai de défilement ils deviennent décoché....MAIS POURQUOI??????
RÉSOLU: j'ai résolu mon problème de getView avec ce code:
public class NewQAAdapterSelectFriends extends BaseAdapter {
private LayoutInflater mInflater;
private Person[] data;
boolean[] checkBoxState;
ViewHolder viewHolder;
public NewQAAdapterSelectFriends(Context context) {
mInflater = LayoutInflater.from(context);
}
public void setData(Person[] data) {
this.data = data;
checkBoxState=new boolean[data.length];
}
@Override
public int getCount() {
return data.length;
}
@Override
public Object getItem(int item) {
return data[item];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_select_friends, null);
viewHolder=new ViewHolder();
viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
}
else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.nameText.setText(data[position].getName());
viewHolder.surnameText.setText(data[position].getSurname());
viewHolder.contactImage.setImageResource(data[position].getPhotoRes());
viewHolder.contactImage.setScaleType(ScaleType.FIT_XY);
viewHolder.checkBox.setChecked(checkBoxState[position]);
viewHolder.checkBox.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(((CheckBox)v).isChecked()){
checkBoxState[position]=true;
data[position].setCheck(true);
}else{
checkBoxState[position]=false;
data[position].setCheck(false);
}
}
});
return convertView;
}
static class ViewHolder {
TextView nameText;
TextView surnameText;
ImageView contactImage;
CheckBox checkBox;
}
}
J'ai vu ce tutoriel pour faire mon getView: http://androidcocktail.blogspot.it/2012/04/adding-checkboxes-to-custom-listview-in.html
- Excellente solution,son travail pour moi
- Juste une question? Qu'est-ce que Personne[] données? Je veux dire à quoi il ressemble?
- La seule solution qui a fonctionné pour moi.
- que faire si l'utilisateur change de commutateur avec pas un clic, plutôt avec un simple glisser? 😛
Vous devez vous connecter pour publier un commentaire.
J'ai résolu mon problème en changeant simplement le "setOnCheckedChangeListener" à "setOnClickListener"
Vérifier le code ci-dessous -
Toujours garder à l'esprit, le changement d'utilisation des
holder.cb.setOnCheckedChangeListener()
c'est à dire n'importe quel auditeur, avant de paramétrage de données, dans notre cas, il estholder.cb.setChecked()
Raison : Lorsque nous défiler, listview recycle les points de vue, donc si setchecked est utilisé avant les auditeurs, alors il sera de choisir les valeurs sur la base de l'ancien auditeur. Et si on l'a mis après l'écoute, puis il va prendre les valeurs les plus récentes
Vous définissez la balise de la case à cocher uniquement si convertview est null. Cela se produit uniquement pour le premier écran de dossiers. Lorsque l'utilisateur fait défiler vers le bas, la précédente convertviews sont recyclés. Ainsi, vos cases à cocher ont de vieux éléments de données que leurs étiquettes.
Vos bagages de changement d'auditeur devrait ressembler à ceci:
Vous n'avez pas à couvrir les cas convertView != null, c'est ce qui arrive lorsque le défilement en haut et en bas. Vous devez mettre en place un moyen de recycler les convertView (mieux) ou tout simplement de les ignorer et de donner un nouveau regard en arrière dans ce cas aussi (pour le pire).
vérifier ce code
J'ai une bonne alternative pour une Case à cocher. Vous pouvez utiliser
android:state_activated="true"
pour votre ListView lignes. Il ne perd pas son état et ne nécessite pas beaucoup de code.Ici est de savoir comment fonctionne
active_row.xml
dans votre dossier drawable<selector xmlns:android="http://schemas.android.com/apk/res/android">
android:background="@drawable/active_row.xml"
android:choiceMode="multipleChoice"
Vous pouvez vérifier l'État de chaque ligne comme ceci
Utilisation setTag() dans l'adaptateur. Vous pouvez voir un exemple ici Exemple listview avec case de défilement problème
Vous devez mettre à jour la carte de conserver la valeur de la case
Pour plus d'aide, vous pouvez consulter ce post dans Conserver la Case de valeur