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

# Androidのドロップダウンリストって名称しか持てないの？
Androidのドロップダウンリスト(spinner)は普通に書くと名称しかドロップダウンリストに持てません。
<img width="20%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933408/bd50d533-bddc-2c47-0317-3881e301c6d8.png">
ドロップダウンリストから選択すると上の例だと「ひとつめ」、「ふたつめ」、「みっつめ」、「よっつめ」のいずれかがリスナAdapterView.OnItemSelectedListener#onItemSelectedに渡されます。

ここでやりたいのはHTMLの\<SELECT\>...\<OPTION\>と同じように、
```HTML
<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だと、たったこんだけです。
```kotlin
data class MyItem(var code: String, var name: String)
```
# ArrayAdapterを継承して独自のAdapterを作る
通常名称しかない場合はArrayAdapter<String>を使いますが、ArrayAdapterを継承して独自のAdapterを作ります。
```kotlin
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したままのメソッドの中身だと。
```kotlin
    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だけなのでこれらのメソッドを細工する必要があります。
```kotlin
    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で受け取り、
```kotlin
textView.text = getItem(position)?.name ?: ""
```
getItem(position)がMyItemを返すので、そこからnameだけを取り出しTextView.textに設定してやります。

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

        val myItemList = ArrayList<MyItem>()
        myItemList.add(MyItem("1", "名称１"))
        myItemList.add(MyItem("2", "名称２"))
        myItemList.add(MyItem("3", "名称３"))
        myItemList.add(MyItem("4", "名称４"))
        myItemList.add(MyItem("5", "名称５"))
        val myAdapter = MyAdapter(this, myItemList)
        spinner.adapter = myAdapter
```
のようになります。ドロップダウンリストが選択された時にのリスナ(onItemSelected)もMyItem.codeだけ欲しいので、
```kotlin
        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<*>?) {
            }
        }
```
の様に、
```kotlin
spinnerParent.selectedItem
```
がMyItemを返すのでそこからcode、nameを別々に取ってやる必要があります。

完成形は[gitHub](https://github.com/cozyk100/AndroidStudioProjectsPublic/tree/main/SpinnerNameValueKotlin)に置きました