ListViewでチェックボックスがずれる問題を解決する


このセクションの概要:

ListView の古典的な問題の 1 つとして、ListView の項目をチェックボックスでカスタマイズしようとした場合、 この問題は、アイテムの数が 1 ページを超える場合に発生します。この問題の原因と解決方法を分析してみましょう。 この問題を解決します!


1. 問題の理由:

これはインターネット上で見つかった ListView getView メソッド呼び出しメカニズムに関する画像です

1.jpg

上の画像には Recycler というものがあります。通常は ListView です。に表示される項目はメモリ内にあり、その項目は次の場所に配置されます。 このリサイクラーでは、アイテムが初めて読み込まれるとき、現在のページの ConvertView は NULL ですが、画面をスクロールアウトすると、今度は ConvertView が空ではないため、新しいアイテムはこの ConvertView! を再利用します。 簡単な例を作成してログを追跡します。実行後のログ図をいくつか示します。

2.png

図からわかるように、位置 12 から ConvertView は空ではなくなりました。これは具体的に何を表しているのでしょうか。 私も分かりません。ソースコードを目視で確認する必要があります。ConvertView がここにキャッシュされるのはこのためです。 チェックボックスの位置がずれているため、最初の解決策は、この ConvertView を再利用しないことです。または、 getViewは毎回このConvertViewをnullに設定するとのことですが、表示する必要のあるItemの数が膨大な場合、 このメソッドは非常に肥大化しているように見えますが、実際の開発では次の解決策を使用します: 現在の項目チェックボックスの状態を保存するものを見つけて、初期化中にそれが選択されているかどうかを判断します。


2. 解決策の例:

このチェックボックスを HashMap<Integer, Boolean> に保存する方法はたくさんあります。 各初期化中に、位置に応じて対応するブール値が取得され、チェックボックスのステータスが設定されます。 著者のアプローチは、判定のためにエンティティ クラスにブール値を追加することです。 以下は著者のプロジェクトの 1 つです。 抽出されたコードは比較的単純なので、数秒で理解できると思います~

Entityクラス: person.java:

public class person implements Serializable{
private String name;
private String number;
private boolean checkStatus;

public person(String name, String number) {
super();
this.name = 名前;
これ。 number = number;
this.checkStatus = false;
}

public String getName() {
return name;
}

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

public String getNumber() {
return number;
}

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

public boolean getCheckStatus() {
return checkStatus;
}

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

}

実装されたアダプタークラス: ContactListAdapter.java:

public class ContactListAdapter extends BaseAdapter implements CompoundButton.OnCheckedChangeListener{

private List<person> mData;
private Context mContext;

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

// 刷新データを決定する方法
public void changeData(List< ;人>データ) {
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 = 新しい 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);
} else {
viewHolder = (View Holder) 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.getタグ();
if ( isChecked)
mData.get(index).setCheckStatus(true);
else
mData.get(index).setCheckStatus(false);
}


プライベート クラス ViewHolder {
RelativeLayout ly;
TextView txtName;
TextView txtNumber ;
チェックボックス cbxStatus;
}
}

これは非常に簡単です。もう 1 つ忘れないでください: チェックボックスの状態を初期化するコードの前にチェックボックス リスナー メソッドを追加する必要があります~


このセクションの概要:

わかりました。 , このセクションでは、ListView のチェックボックスが間違っているという典型的な問題について説明します。 この問題は、チェックボックスの選択状態を記録する値を追加し、チェックボックスを書き換えるだけで解決します。 イベントをクリックするときは、まず判断してください~ありがとう~