Adapterを利用したListViewにおける選択行以外の行の操作について

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 130

ss1234

score 10

Adapterを使ったListViewにて、ラジオボタンのような挙動をListViewの背景色でできないかと(選択した行の背景色を変え、背景色が変わっている行は背景色を戻す)検討しています。
Clickイベント(下記ListItemAdapter.GetView()内)で選択した行への操作はできるのですが、他の行への操作方法が分かりません。
そもそもやり方が間違っているのか、ご教授お願いいたします。

開発環境:VisualStudio2017pro

Activity.cs OnCreate()内ListView生成部分

var list = new List<ListItem>();
list.Add(new ListItem() { MyText="row1" });
list.Add(new ListItem() { MyText="row2" });
list.Add(new ListItem() { MyText="row3" });
var listView = FindViewById<ListView>(Resource.Id.myListView);
listView.Adapter = new ListItemAdapter(this, 0, list);

CustomAdapter

public class ListItemAdapter : ArrayAdapter<ListItem>
{
   private readonly LayoutInflater _layoutInflater;
   public ListItemAdapter(Context context, int rid, IList<ListItem> list)
   : base(context, rid, list)
   {
      _layoutInflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
   }
   public override View GetView(int position, View convertView, ViewGroup parent)
   {
      var item = GetItem(position);
      var view = _layoutInflater.Inflate(Resource.Layout.custom_list_view, null);
      var textView = view.FindViewById<TextView>(Resource.Id.myText);
      textView.Text = item.MyText;

      // リスト選択(クリックイベント)
      view.Click += (sender, e) =>
      {
          view.SetBackgroundColor(Android.Graphics.Color.Red);
          // ここで他の行を取得して、背景色を操作したい
      };
      return view;
   }
}

ListItemAdapterから参照するview(custom_list_view.axml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout  xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:background="#FFDAFF7F"
   android:padding="8dp">
   <LinearLayout 
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:id="@+id/linearLayout1">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/myText"
            android:textSize="20dp"/>
    </LinearLayout>
</RelativeLayout >
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

java の ListView と同じ構造なのか分かりませんが, 一応「java では」ということで参考になればと思います.

ListView は基本的に getView が返した View を表示するだけです.
ですので, 表示に必要な情報は Adapter に保持しておく必要があります.
件の場合, クリックしたことで背景色を直接更新していますが, これだけでは再表示した際には元に戻ってしまいます.
ラジオボタンのような動作をさせるのでしたら, どの行が選択状態なのか(=背景色を変える行はどこか)を保持しておく必要は当然ありますし, それを元に getView で「その行だったら背景色を Red, 違うなら White(?) 」という処理を入れます.
これで, 最後にクリックされた行の getView だけが背景色の違う View を返すことになりますので, その前にクリックされていた行は背景色が戻るようになります.
ですが, これだけではその「先にクリックされていた行」は再表示されません. そこで, 再表示が必要であることを示す「その行のデータが変更された」というメッセージ(notify~) を Adapter のメソッドで ListView に投げます. すると ListView がその行の getView を呼び, 返された(背景色が戻った) View を再表示してくれます.

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/08/29 15:27

    ご回答ありがとうございます。javaでもxamarinでもおそらく流れは同じかと思っております。
    ListViewに表示してあるコレクションを保持し、クリックイベント等で保持してあるコレクションを更新→notifyDataSetChanged?でリスト全体を更新(画面の更新)するようになるのでしょうか。

    キャンセル

  • 2019/08/30 02:12

    ListView に表示してあるコレクションは, Adapter が保持していると思います. (それが Adapter の役割ですので.)

    クリックイベントで何を更新するかに付きましては, ラジオボタンとして「どれが ON になっているか」をどう保持するかによると思います.
    例えば, Adapter に ListItem 型の変数 (仮に)A を用意し, それが ON になっている行(の ListItem 型変数)を指すことにすれば, getView では getItem で得た ListItem が A だったら背景色を変えるようにすることで現在の選択行を示せますし, クリックイベントで A をその行(の ListItem 型変数) に変更することで ON を切り替えることが出来ると思います.
    ListItem に選択状態を Boolean 等で持たせると, クリックイベントで元 ON の行を OFF にするために list 内を探さないといけませんので, 僅かに面倒でしょうか.

    画面の更新に関しましては, notifyDataSetChanged による全体の更新の他, 恐らく1行毎の notify もあるのではないでしょうか. まぁ, どちらが良いかは主に件数で判断されると思いますので, ラジオボタンの代わりとしては精々10件等でしょうし, 全体更新でも良いかも知れません.

    キャンセル

  • 2019/08/30 18:00

    jimbe様
    なるほど、道筋が見えた気がします。他業務が忙しく、コードをいじれていませんが、トライしてみます。
    結果はまたこちらにご報告させていただきます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる