Résoudre le problème du désalignement des cases à cocher dans ListView


Introduction à cette section :

Comme l'un des problèmes classiques de ListView, si vous avez essayé de personnaliser l'élément de ListView avec une case à cocher dessus, alors Ce problème se produira lorsque le nombre de vos éléments dépasse une page. Analysons les raisons de ce problème et comment le résoudre. Résolvez ce problème !


1. Cause du problème :

Il s'agit d'une image trouvée sur Internet concernant le mécanisme d'appel de la méthode ListView getView

1.jpg

Il y a un Recycleur dans l'image ci-dessus. Habituellement, l'élément visible sur notre ListView est dans la mémoire et son élément est placé dans. Dans ce Recycler, lorsque l'élément est chargé pour la première fois, le convertView dans la page actuelle est NULL Lors du défilement hors de l'écran, cette fois ConvertView n'est pas vide, donc le nouvel élément le réutilisera. ConvertView ! Nous pouvons écrire un exemple simple et suivre le journal. Voici quelques diagrammes de journal après l'exécution !

2.png

Comme le montre l'image, à partir de la position 12, ConvertView n'est plus vide. Que représente-t-il spécifiquement ? Je ne sais pas, je dois parcourir le code source visuellement... Nous savons que ConvertView sera mis en cache ici, juste pour cette raison La case à cocher est mal alignée, donc la première solution est de ne pas réutiliser ce ConvertView, ou On dit qu'à chaque fois, getView définit ce ConvertView sur null, mais si le nombre d'éléments à afficher est énorme, Cette méthode semblera très lourde. Généralement, dans le développement réel, nous utilisons la solution suivante : Trouvez quelque chose pour enregistrer l'état de l'Item CheckBox actuel, et jugez-le lors de l'initialisation pour définir s'il est sélectionné !


2. Exemple de solution :

Il existe de nombreuses bonnes façons de stocker cette case à cocher, vous pouvez la mettre dans un HashMap<Integer, Boolean> Lors de chaque initialisation, la valeur booléenne correspondante est extraite en fonction de la position, puis l'état de la case à cocher est défini ; L'approche de l'auteur consiste à ajouter une valeur booléenne à la classe d'entité à des fins de jugement. Ce qui suit est l'un des projets de l'auteur. Le code extrait est relativement simple. Je pense que vous le comprendrez en quelques secondes après l'avoir lu ~

Classe d'entité : Person.java:

classe publique Person implémente Sérialisable{
    private String name ;
    private String number;
    private boolean checkStatus;
    
    public Person(String name, String number) {
        super();
        this.name = name;
        this.number = number;
        this.checkStatus = false;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNumber() {
        numéro de retour ;
    }

    public void setNumber(String number) {
        this.number = numéro;
    }

    public boolean getCheckStatus() {
return checkStatus;
    }

    public void setCheckStatus(boolean checkStatus) {
        this.checkStatus = checkStatus;
    }
    
}

Classe d'adaptateur implémentée : ContactListAdapter.java :

classe publique ContactListAdapter étend BaseAdapter implémente CompoundButton.OnCheckedChangeListener{

    private List<Person> mData;
    private Context mContext;

    public ContactListAdapter(List<Person> data, Context context) {
        mData = data;
        mContext = context;
    }

    // 定义一个刷新数据的方法
    public void changeData(List<Person> data) {
        mData = data;
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Person getItem(int position) {
       return mData.get( position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView (int position, View convertView, ViewGroup parent) {
        final int index = position;
        ViewHolder viewHolder;
        if (convertView == null) {
             convertView = LayoutInflater.from(mContext).inflate (
                    R.layout.item_contact, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.ly = (RelativeLayout) convertView
                    .findViewById(R.id.lyContactListItem);
            viewHolder.txtName = (TextView) convertView
                    .findViewById(R.id.txtName);
            viewHolder.txtNumber = (TextView) convertView
                    .findViewById(R.id.txtNumber);
            viewHolder. cbxStatus = (CheckBox) convertView
                    .findViewById(R.id.cbxStatus);
            convertView.setTag(viewHolder);
            viewHolder.cbxStatus.setTag(index );
        } autre {
viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.cbxStatus.setOnCheckedChangeListener(this);
        viewHolder.cbxStatus.setChecked(mData.get(position).getcheckStatus());
        viewHolder.txtName.setText(mData.get(index).getName());
        viewHolder.txtNumber.setText(mData.get(index).getNumber());
        return convertView;
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        int index = (int)buttonView.getTag();
       if (isChecked)
            mData.get (index) ly ;
        TextView txtName;
        TextView txtNumber;
        CheckBox cbxStatus;
>
}

Hé, c'est très simple, n'oubliez pas encore une chose : La méthode d'écoute de case à cocher doit être ajoutée avant le code qui initialise l'état de la case à cocher~


Introduction à cette section :

Bon, cette section vous explique un problème classique de ListView, la case à cocher dans ListView est mal placée Le problème est résolu en ajoutant simplement une valeur qui enregistre l'état de sélection de la case à cocher, puis en réécrivant la case à cocher Lorsque vous cliquez sur un événement, portez d'abord un jugement~Merci~