ListViewの選択されたアイテムの背景色を変更2

[Android] ListViewの選択されたアイテムの背景色を変更では、ListViewの行のレイアウトのbackgroundに以下のselectorを設定して選択された行の背景色を変更しました。

res/drawable/list_item_selector.xml



android:drawable="@color/selected_list_item_color"/>
android:drawable="@color/selected_list_item_color"/>


res/values/colors.xml



#ffd33f
#000000
#00000000

しかし、この方法では画面の中にListView以外にテキストボックスなどが存在して、ListViewからフォーカスが外れると行の選択状態が解除されてしまいます。

これを防ぐためには以下のようにListViewにandroid:choiceMode=”singleChoice”を設定し、行のレイアウトもCheckableを継承したカスタムレイアウトを設定する必要があります。

        android:id="@+id/unit_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:choiceMode="singleChoice"
/>

方法はこちらのブログで詳しく解説されています。私の記事のサンプルコードはScalaなので、Javaのサンプルコードはこちらのブログを参考にして下さい。

Y.A.M の 雑記帳: Android DrawableState でリストアイテムの背景を変える ViewGroup を作る

singleChoiceではCheckableを継承したレイアウトが必要になるので、RelativeLayoutとCheckableを継承したカスタムレイアウトを作成します。

object CheckableRelativeLayout {
private val CHECKED_STATE_SET = Array[Int](android.R.attr.state_checked)
}

class CheckableRelativeLayout(context: Context, attrs: AttributeSet, defStyle: Int) extends RelativeLayout(context, attrs, defStyle) with Checkable {
def this(context: Context, attrs: AttributeSet) = this(context, attrs, 0)
def this(context: Context) = this(context, null)

private var checked = false

def setChecked(checked: Boolean) {
if (this.checked != checked) {
this.checked = checked
refreshDrawableState()
}
}

def isChecked: Boolean = checked

def toggle() = setChecked(!checked)

override def onCreateDrawableState(extraSpace: Int) = {
val drawableState = super.onCreateDrawableState(extraSpace + 1)
if (isChecked) {
View.mergeDrawableStates(drawableState, CheckableRelativeLayout.CHECKED_STATE_SET)
}
drawableState
}
}

list_row.xml

ListViewの行のレイアウトで使用していたRelativeLayoutを上記のカスタムレイアウトに置き換えます。


xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_item_selector"
>
android:id="@+id/symbol_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="symbol"
android:textColor="@color/white"
/>
android:id="@+id/value_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="0"
android:textColor="@color/white"
/>

res/drawable/list_item_selector.xml



android:drawable="@color/selected_list_item_color"/>


これで行をタップすると行の背景が変わり、フォーカスを失っても背景が変わったままになります。

ListViewをタップした時に色を変えないようにする

上記の変更を行うと、ListViewをタップして指を離してから選択行の色が変更されます。

ListViewはデフォルトではタップした時にも色が変わるようになっているので、タップして指を離すまでは背景色が2つの行で変更されてしまいます。
タップした時に色を変えない方法は別の記事にまとめましたので、この挙動が嫌な場合は以下の記事を参考にタップした行の色を変えないようにして下さい。

[Android] ListViewをタップした時に色を変えないようにする