2
1

More than 3 years have passed since last update.

Android Studioのチェック付きListViewでスクロールするとチェックの状態が変わってしまう(解決)

Posted at

チェックの状態が変わってしまう

まず、スクロールするほどのチェックを追加したとして、それでスクロールしたらなぜかチェックの状態が変わってしまうのです。

↑のように、アイテム1がチェックされていない状態でスタートして、

↑のように、アイテム1にチェックを入れます。

↑のように、下にスクロールします。

すると、なんと↑のように、チェックの状態が変わってしまうのです。(アイテム1が。)

変わってしまう理由

まず、画面外になってしまった場合はその項目は廃棄されます。(再利用される)
独自adapterのコードではgetView(...)というところがありますよね。
それは各行が読み込まれたときに呼ばれる関数なんです。
廃棄されるので、そのgetViewのところでもっかい反映させないといけないんです。

チェックリストのコードは大きく分けて二つの種類

・SimpleAdapter
・ArrayAdapter

(listViewDataは独自のclassの名前)

SimpleAdapter

これは主にMapを使う方法です。Mapに"check"と"name"を作成して、それをputする感じです。
しかし、この方法だとダメでした。
だめというか、自分の知能だと解決できませんでした。getItem(position)などから
チェックの状態を反映させてもだめでした。

ArrayAdapter

この方法を使って解決しました。
これは独自のclassからsetTextDataとかをしたりsetCheckedをしたりgetTextDataからgetViewのところでセットしたり、
getCheckedからgetViewのところでセットしたりとする感じです。
なかなかこの説明では理解しずらいと思いますが、まぁこの方法を使えば解決できるということです。

どこをどのように変更したのか

まず、SimpleAdapterを使うのは無理だと分かったので、ArrayAdapterを継承したやつにしまた。

そして独自AdapterのgetViewのところをこうしました。

MyAdapter.java
    public View getView(int position, View convertView, ViewGroup parent) {
        // 特定行(position)のデータを得る
        MyData item = (MyData)getItem(position);
        // convertViewは使いまわされている可能性があるのでnullの時だけ新しく作る
        if (null == convertView) convertView = mLayoutInflater.inflate(R.layout.list, null);

        // MyDataのデータをViewの各Widgetにセットする
        TextView textView = convertView.findViewById(R.id.textView);
        textView.setText(item.getTextData());
        CheckBox checkBox = convertView.findViewById(R.id.checkBox);
        checkBox.setOnCheckedChangeListener(null);
        checkBox.setChecked(item.isChecked());
        checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                MyData MyData = getItem(position);
                MyData.setChecked(b);
            }
        });

        return convertView;
    }

まず最初に注目してほしいのがここです。

        // MyDataのデータをViewの各Widgetにセットする
        TextView textView = convertView.findViewById(R.id.textView);
        textView.setText(item.getTextData());
        CheckBox checkBox = convertView.findViewById(R.id.checkBox);
        checkBox.setOnCheckedChangeListener(null);
        checkBox.setChecked(item.isChecked());

この行がないと、なにもないチェックの状態もfalseでtextViewのデータも空の状態になってしまいます。
checkBoxは念のため、リスナーを外してから、反映しています。

そしてからcheckBoxにチェンジリスナ―を付けました。

また、

        checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                MyData MyData = getItem(position);
                MyData.setChecked(b);
            }
        });

というふうに、チェンジリスナーをつけておかないと、ずっとチェックがfalseになってしまうため、スクロールして画面外になると勝手にチェックが外されるといった挙動になります。

実際に作ってみました↓
Android Studio の ListView に CheckBox を追加する | チェックリストを作成

参考:
[Android][Java] ListViewのCheckBoxの状態を管理する

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1