LoginSignup
0
1

More than 1 year has passed since last update.

AndroidでHTMLの<SELECT>...<OPTION...>のように名前と値を対比してSpinnerを表示する

Last updated at Posted at 2022-11-23

Androidのドロップダウンリストって名称しか持てないの?

Androidのドロップダウンリスト(spinner)は普通に書くと名称しかドロップダウンリストに持てません。

ドロップダウンリストから選択すると上の例だと「ひとつめ」、「ふたつめ」、「みっつめ」、「よっつめ」のいずれかがリスナAdapterView.OnItemSelectedListener#onItemSelectedに渡されます。

ここでやりたいのはHTMLの<SELECT>...<OPTION>と同じように、

<select name="choice">
    <option value="1">ひとつめ</option>
    <option value="2">ふたつめ</option>
    <option value="3">みっつめ</option>
    <option value="4">よっつめ</option>
</select>

といったように
「ひとつめ」を選択 → 1 がonItemSelectedに渡されるようにする
「ふたつめ」を選択 → 2 がonItemSelectedに渡されるようにする
「みっつめ」を選択 → 3 がonItemSelectedに渡されるようにする
「よっつめ」を選択 → 4 がonItemSelectedに渡されるようにする
にしたいです。

名称と値のペアを保持するデータクラスを作る

名称と値のペアを保持するデータクラスを作ります。kotlinだと、たったこんだけです。

data class MyItem(var code: String, var name: String)

ArrayAdapterを継承して独自のAdapterを作る

通常名称しかない場合はArrayAdapterを使いますが、ArrayAdapterを継承して独自のAdapterを作ります。

class MyAdapter(context: Context, list: ArrayList<MyItem>) :
    ArrayAdapter<MyItem>(context, android.R.layout.simple_spinner_item, list) {

    init {
        setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
    }
    ・・・
}

MyAdapterのメソッドのoverride

このMyAdapterのコンストラクタの2番めの引数がドロップダウンリストに表示したい名称と値のペア、そのリストです。この、MyAdapterのメソッドをふたつoverrideしてやる必要があります。overrideしたままのメソッドの中身だと。

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        return super.getView(position, convertView, parent)
    }

    override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
        return super.getDropDownView(position, convertView, parent)
    }

ですが、このまだだと、MyItem#toString()の結果がドロップダウンリストにでてしまいます。出てほしいのはMyItem.nameだけなのでこれらのメソッドを細工する必要があります。

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val textView = super.getView(position, convertView, parent) as TextView
        textView.text = getItem(position)?.name ?: ""
        return textView
    }

    override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
        val textView = super.getDropDownView(position, convertView, parent) as TextView
        textView.text = getItem(position)?.name ?: ""
        return textView
    }

ここのミソは、overrideしただけの処理はいきなりTextViewを返していますが、一旦TextViewで受け取り、

textView.text = getItem(position)?.name ?: ""

getItem(position)がMyItemを返すので、そこからnameだけを取り出しTextView.textに設定してやります。

このふたつのメソッドの違いですが、わかりずらくて・・・
getView は選択中の項目の表示レイアウトを生成します。なのでドロップダウンリストにフォーカスが当たってない時の表示。
getDropDownView はリストのレイアウトを生成まます。ドロップダウンリストにフォーカスが当たった時の表示。

ドロップダウンリストにリストを設定する側

ドロップダウンリストにリストを設定する側は

        val spinner = binding.spinner

        val myItemList = ArrayList<MyItem>()
        myItemList.add(MyItem("1", "名称1"))
        myItemList.add(MyItem("2", "名称2"))
        myItemList.add(MyItem("3", "名称3"))
        myItemList.add(MyItem("4", "名称4"))
        myItemList.add(MyItem("5", "名称5"))
        val myAdapter = MyAdapter(this, myItemList)
        spinner.adapter = myAdapter

のようになります。ドロップダウンリストが選択された時にのリスナ(onItemSelected)もMyItem.codeだけ欲しいので、

        spinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>?,view: View?, position: Int, id: Long) {
                val spinnerParent = parent as Spinner
                val myItem = spinnerParent.selectedItem as MyItem
                Log.d("MyAdapter", "${myItem.name} = ${myItem.code}が選択されました")
            }

            override fun onNothingSelected(p0: AdapterView<*>?) {
            }
        }

の様に、

spinnerParent.selectedItem

がMyItemを返すのでそこからcode、nameを別々に取ってやる必要があります。

完成形はgitHubに置きました

0
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
0
1