ListViewの選択された項目の色を変える方法(Android Studio Kotlin)

,

Androidのアプリ作成で、ListViewの項目を選択した時に、ListViewの選択項目部分の色を変えたい場合の対処方法に関して記載します。

1.対処例の画面

ListViewの選択項目の部分の色が変わるように作成したアプリ例の動画です。
選択した項目の部分の色が変わります。また選択項目は下のTextView部分に表示されます。

2.開発環境等

開発ツールバージョン: Android Studio Giraffe 2022.3.1 Path3
使用言語: Kotlin

3.対処方法

カスタムアダプタを作成して、そのgetView()メソッドに選択行のTextViewのバックカラーを変える処理を設ける。

4.対処例の部品配置

図1の様に部品を配置した場合の例を示します。(ConstraintLayout使用)

図1.部品配置図

5.レイアウトのxmlコード

図1のレイアウトのxmlコード(app→res→layout→activity_main.xml)を以下に示します。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/listView1"
        android:layout_width="370dp"
        android:layout_height="268dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="32dp"
        android:background="#00bcd4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="32dp"
        android:text="選択された項目"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/listView1" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="369dp"
        android:layout_height="37dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:background="@color/design_default_color_secondary"
        android:textSize="24sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView1" />

</androidx.constraintlayout.widget.ConstraintLayout>

【説明】
9行目~17行目:
ListView部分の記述です。

29行目~38行目:
ListViewから選択された項目を表示するTextViewに関する記述です。

6.ListViewの項目1行分レイアウトのxmlコード

カスタムアダプタで使用するListViewの項目1行分のレイアウトのxmlコードを以下に示します。(app→res→values→layout_item.xml)
ここでは、TextViewを1個だけ配置しました。このTextViewのidは、item_textviewとしています。このidはカスタムアダプタ内でListViewの選択行の色を変えるのに、TextViewのバックカラーを変更しますが、その際に使用します。
また、layout_item.xmlファイルの名称「layout_item」は、カスタムアダプタ内で1行分のレイアウトを作成する際に使用します。

<?xml version="1.0" encoding="utf-8"?>

<!--ListViewのアイテムのレイアウト指定 (TextViewを1個配置)-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingStart="10dp"
    android:paddingEnd="10dp"
    android:paddingTop = "10dp"
    android:paddingBottom="10dp"
    android:textColor = "#000000">
</TextView>

7.カスタムアダプタのソースコード

カスタムアダプタクラスのソースコードを以下に示します。
カスタムアダプタクラスはインナークラスとしてMainActivityクラス内に作成しました。
カスタムアダプタクラスの引数selItemNoで、ListViewの色を変える行を指定するようになっています。

    //ListView用カスタムアダプタ(引数selItemNoで指定した行のバックカラーを変える)
    inner class CustomAdapter(context: Context, list: Array<String>, selItemNo: Int) : ArrayAdapter<String>(context,0,list) {
        private val selNo = selItemNo   //選択項目ポジション

        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
            var view = convertView
            if (view == null){
                //アイテム1行分のレイアウト生成
                view = LayoutInflater.from(context).inflate(R.layout.layout_item, parent, false)
            }

            val text = getItem(position)    //アイテム1行分のテキスト取得

            //アイテムレイアウトのTextView取得
            val TexViw = view?.findViewById<TextView>(R.id.item_textView)

            //selNo(選択行)と一致する行のアイテムのTextViewのバックカラーを変える
            if (position == selNo){         //選択された項目のバックカラー設定
                TexViw?.setBackgroundColor(Color.GREEN)
            }else{                          //選択されてない項目のバックカラー設定
                TexViw?.setBackgroundColor(Color.rgb(0x00, 0xbc, 0xd4))
            }

            //アイテムのTextViewにテキストセット
            TexViw?.setText(text)

            return view!!
        }
    }

【説明】
5行目:
getView()メソッドは、カスタムアダプタをListViewにセットすると行番号に相当する引数(position)の値を0,1,2—と変えてListViewの行数分呼び出されます。getView()メソッド内で、それぞれの行への項目の設定等を行います。(但し、getView()メソッドはスクロールがある場合は、そのスクロール位置で表示されている行の分だけ呼び出されるようです)

9行目:
view = LayoutInflater.from(context).inflate(R.layout.layout_item, parent, false) でListViewの項目1行分のレイアウトを生成します。
第1引数のR.layout.layout_itemが6項に記述したレイアウトファイルlayout_item.xmlを表します。

15行目:
val TexViw = view?.findViewById<TextView>(R.id.item_textView) で項目1行分のレイアウト要素のTextViewを取得します。
引数のR.id.item_textViewは6項に記述したlayout_item.xmlのTextViewのidです。

18行目~22行目:
CustomAdapterクラスの引数selItemNoは、ListViewの選択行のポジションで、それをselNoに代入して、それがpositionと一致した時に、選択された行が処理されているので、そのTextViewのバックカラーを変えています。

8.MainActivityクラスのonCreate()メソッドのソースコード

アプリ起動時の最初に実行されるMainActivityクラスのonCreate()メソッドのソースコードを以下に示します。ここでListView関係の初期処理を行っています。

  override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //カスタムアダプタを構築
        //第3引数「-1」は色を変えるアイテムのポジションで、色を変える部分無
        val addapter = CustomAdapter(this@MainActivity, items, -1)
        //リストビューにアダプタ設定
        val listView1 = findViewById<ListView>(R.id.listView1)
        listView1.adapter= addapter

        //ListViewのアイテムが選択された時のリスナ登録
        listView1.onItemClickListener = listView1ClickListener()
    }

【説明】
7行目~10行目:
カスタムアダプタを構築してListViewにセットしています。
CustomAdapter()の第3引数の「-1」は、色を変える行の位置を指定しています。この値がマイナスの場合は色を変える行はありません。

13行目:
ListViewの項目が選択された時に呼び出されるリスナを登録しています。

9.ListViewの項目が選択された時のリスナクラスのソースコード

ListViewの項目が選択された時に呼び出されるリスナのソースコードを以下に示します。
選択行の色を変えたアダプタを再構築してListViewにセットしています。

    //ListViewのアイテムが選択された時、呼び出されるリスナクラス
    private inner class listView1ClickListener: AdapterView.OnItemClickListener{
        override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
            val item = parent?.getItemAtPosition(position) as String   //選択されたアイテム取り出し

            //TextViewに選択したアイテム表示
            val textView = findViewById<TextView>(R.id.textView2)
            textView.text = item

            //----ListViewの選択されたアイテム部分の色を変える----
            //現在のListViewスクロール位置記憶
            val listView = findViewById<ListView>(R.id.listView1)
            val scrollPos = listView.firstVisiblePosition   //先頭行のポジション取得
            val y_pos = listView.getChildAt(0).top    //先頭行のスクロール位置(ピクセル)取得

            //アダプタの再構築(第3引数positionで選択されたアイテム部分の色が変わる)
            val addapter = CustomAdapter(this@MainActivity, items, position)
            //リストビューに再構築したアダプタ設定
            listView.adapter= addapter

            //スクロール位置を元のスクロール位置に戻す
            listView.setSelectionFromTop(scrollPos, y_pos)
        }
    }

【説明】
12行目~14行目:
ListViewがスクロールしている場合にアダプタを再セットするとスクロール位置が先頭に戻ってしまいます。それを防ぐためにアダプタを再セットする前に現在のスクロール位置を記憶しておきます。
val scrollPos = listView.firstVisiblePosition は、スクロールした状態で最上位位置に表示される項目のポジション値を呼び出します。
val y_pos = listView.getChildAt(0).top はスクロールが行の中途半端な位置にいる量をピクセル単位で呼び出します。

17行目~19行目:
val addapter = CustomAdapter(this@MainActivity, items, position) でアダプタを再構築します。position変数に選択された行位置が入っているので、それを指定してその部分の色を変更したアダプタを構築し、listView.adapter= addapter でListViewに設定します。

22行目:
アダプタを再セット後に listView.setSelectionFromTop(scrollPos, y_pos)で、記憶したスクロール位置へ戻します。

10.全ソースコード

Kotlinプログラム(MainActiviryクラス)の全ソースコードを以下に示します。

class MainActivity : AppCompatActivity() {
    //ListViewの項目
    val items = arrayOf("項目1","項目2","項目3","項目4","項目5",
        "項目6","項目7","項目8","項目9","項目10",
        "項目11","項目12","項目13","項目14","項目15",
        "項目16","項目17","項目18","項目19","項目20")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //カスタムアダプタを構築
        //第3引数「-1」は色を変えるアイテムのポジションで、色を変える部分無
        val addapter = CustomAdapter(this@MainActivity, items, -1)
        //リストビューにアダプタ設定
        val listView1 = findViewById<ListView>(R.id.listView1)
        listView1.adapter= addapter

        //ListViewのアイテムが選択された時のリスナ登録
        listView1.onItemClickListener = listView1ClickListener()
    }

    //ListViewのアイテムが選択された時、呼び出されるリスナクラス
    private inner class listView1ClickListener: AdapterView.OnItemClickListener{
        override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
            val item = parent?.getItemAtPosition(position) as String   //選択されたアイテム取り出し

            //TextViewに選択したアイテム表示
            val textView = findViewById<TextView>(R.id.textView2)
            textView.text = item

            //----ListViewの選択されたアイテム部分の色を変える----
            //現在のListViewスクロール位置記憶
            val listView = findViewById<ListView>(R.id.listView1)
            val scrollPos = listView.firstVisiblePosition   //先頭行のポジション取得
            val y_pos = listView.getChildAt(0).top    //先頭行のスクロール位置(ピクセル)取得

            //アダプタの再構築(第3引数positionで選択されたアイテム部分の色が変わる)
            val addapter = CustomAdapter(this@MainActivity, items, position)
            //リストビューに再構築したアダプタ設定
            listView.adapter= addapter

            //スクロール位置を元のスクロール位置に戻す
            listView.setSelectionFromTop(scrollPos, y_pos)
        }
    }

    //ListView用カスタムアダプタ(引数selItemNoで指定した行のバックカラーを変える)
    inner class CustomAdapter(context: Context, list: Array<String>, selItemNo: Int) : ArrayAdapter<String>(context,0,list) {
        private val selNo = selItemNo   //選択項目ポジション

        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
            var view = convertView
            if (view == null){
                //アイテム1行分のレイアウト生成
                view = LayoutInflater.from(context).inflate(R.layout.layout_item, parent, false)
            }

            val text = getItem(position)    //アイテム1行分のテキスト取得

            //アイテムレイアウトのTextView取得
            var TexViw = view?.findViewById<TextView>(R.id.item_textView)

            //selNo(選択行)と一致する行のアイテムのTextViewのバックカラーを変える
            if (position == selNo){         //選択された項目のバックカラー設定
                TexViw?.setBackgroundColor(Color.GREEN)
            }else{                          //選択されてない項目のバックカラー設定
                TexViw?.setBackgroundColor(Color.rgb(0x00, 0xbc, 0xd4))
            }

            //アイテムのTextViewにテキストセット
            TexViw?.setText(text)

            return view!!
        }
    }
}

PAGE TOP