2013年7月18日木曜日

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

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

res/drawable/list_item_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_selected="true"
        android:drawable="@color/selected_list_item_color"/>
  <item android:state_pressed="true"
    android:drawable="@color/selected_list_item_color"/>
  <item android:drawable="@color/default_color"/>
</selector>

res/values/colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <color name="selected_list_item_color">#ffd33f</color>
  <color name="default_color">#000000</color>
  <color name="clear">#00000000</color>
</resources>

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

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

  <ListView
      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を上記のカスタムレイアウトに置き換えます。

<?xml version="1.0" encoding="utf-8"?>
<com.shinichy.convertBox.CheckableRelativeLayout
    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"
    >
  <TextView
      android:id="@+id/symbol_text"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="symbol"
      android:textColor="@color/white"
      />
  <TextView
      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"
      />
</com.shinichy.convertBox.CheckableRelativeLayout>

res/drawable/list_item_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_checked="true"
    android:drawable="@color/selected_list_item_color"/>
  <item android:drawable="@color/clear"/>    
</selector>

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

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

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

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

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

0 件のコメント:

コメントを投稿