Kotlin ArrayAdapterにデータクラスを渡す

ArrayAdapterをカスタムして自作のデータクラスを渡します。
`AutoCompleteTextView`のフィルターをカスタマイズしようとしたところ思ったより多くの情報が得られたのでまとめました。
フィルターをカスタマイズしただけの記事も書きます。

目次

1.[今回扱うデータクラス](#今回使うデータクラスです)
2.[アダプターの作成](#adapterを作る)
3.[実際に使う](#autocompletetextviewで使う)
4.[完成したもの](#完成したもの)
5.[最後に](#最後に)

# 今回使うデータクラス
```kotlin
data class Fruit(
    val name:String,
    val color:String,
    val price:Int,
    val id:Int)
```

# Adapterを作る
Adapterのコード全文です。コードだけでいい人はどうぞ。
下で解説しています。

```kotlin.kt
class FruitAdapter(context: Context, @LayoutRes private val layoutResource: Int, private val allItems: MutableList<Fruit>):
        ArrayAdapter<Fruit>(context,layoutResource,allItems),
        Filterable{
    private var mutableAllItems:MutableList<Fruit> = allItems

    override fun getCount(): Int {
        return mutableAllItems.size
    }

    override fun getItem(position: Int): Fruit? {
        return mutableAllItems[position]
    }

    override fun getItemId(position: Int): Long {
        return mutableAllItems[position].id.toLong()
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view: TextView = convertView as TextView? ?: LayoutInflater.from(context).inflate(layoutResource,parent,false) as TextView
        val info = mutableAllItems[position]
        view.text = "${info.name}${info.color}${info.price}"
        return view
    }

    override fun getFilter(): Filter {
        return object: Filter(){
            override fun publishResults(charSequence: CharSequence?, filterResults: FilterResults? ){
                if (filterResults != null) {
                    mutableAllItems = filterResults.values  as MutableList<Fruit>
                    if(filterResults.count > 0)
                        notifyDataSetChanged()
                    else
                        notifyDataSetInvalidated()
                }
            }

            override fun performFiltering(charSequence: CharSequence?): FilterResults {
                val filterResults = FilterResults()

                val newItems =
                    if (charSequence==null || charSequence.isEmpty())
                        allItems
                    else
                        allItems.filter {it.name.startWith(charSequence) || it.color.strartWith(charSequence)}

                filterResults.values = newItems
                filterResults.count = newItems.size
                return filterResults
            }
        }
    }
        }
```
---
```kotlin.kt
class SampleAdapter(context: Context, @LayoutRes private val layoutResource: Int, private val allItems: MutableList<Fruit>):
        ArrayAdapter<Fruit>(context,layoutResource,allItems),
        Filterable{
        //中身は以下
        }
```
継承関係です。`allItems`は`MutableList`で作成しました。配列やコレクションだったらなんでもいいはずです。勿論それによってコードは変わっていきます。

---
```kotlin:Filterable
private var mutableAllItems:MutableList<Fruit> = allItems
```
フィルターで絞り込んでいくときに使われる変数です。

---
```kotlin:Filterable
override fun getCount(): Int {
    return mutableAllItems.size
}
```
絞り込まれた要素数を返します。

---
```kotlin:Filterable
override fun getItem(position: Int): Fruit? {
    return mutableAllItems[position]
}
```
1列分のデータを返します。
アダプター作成時に定義したデータ型を返す必要があります。

---
```kotlin:Filterable
override fun getItemId(position: Int): Long {
    return mutableAllItems[position].id.toLong()
}
```
idを自分で決めるならオーバーライドします。
オーバーライドしなくても動きます。

---
```kotlin:Filterable
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
    val view: TextView = convertView as TextView? ?: LayoutInflater.from(context).inflate(layoutResource,parent,false) as TextView
    val info = mutableAllItems[position]
    view.text = "${info.name}${info.color}${info.price}"
    return view
}
```
一列分のViewを返します。シンプルに`TextView`を返しています。
`Array<String>`等で`allItems`を定義しているならオーバーライドしなくてもデータが`String`なので綺麗に表示されます。

---
```kotlin:Filterable
override fun getFilter(): Filter {
    return object: Filter(){
        //中身は以下
    }
}

```
配列の要素を変えたのとフィルターも作り直す必要があります。
フィルターを呼び出さない用途なら必要ないかもしれません。
この中で`publisResults`と`performFiltering`をオーバーライドする必要があります。

---
```kotlin:Filter( )
override fun publishResults(charSequence: CharSequence?, filterResults: FilterResults? ){
    if (filterResults != null) {
        mutableAllItems = filterResults.values  as MutableList<Fruit>
        if(filterResults.count > 0)
            notifyDataSetChanged()
        else
            notifyDataSetInvalidated()
    }
}
```
`charSequence`はフィルターするために使われた文字列です。
`filterResults`はフィルターされたリストが入っていて、これをアダプター全体と共有します。

---
```kotlin:Filter( )
override fun performFiltering(charSequence: CharSequence?): FilterResults {
    val filterResults = FilterResults()

    val newItems =
        if (charSequence==null || charSequence.isEmpty())
            allItems
        else
            allItems.filter {it.name.startWith(charSequence) || it.color.startWith(charSequence)}
    filterResults.values = newItems
    filterResults.count = newItems.size
    return filterResults
}
```
実際にフィルターにかける部分です。
`charSequence`はフィルターするための文字列が与えられます。

# AutoCompleteTextViewで使う
xmlファイルは`AutoCompleteTextView`置いただけなので省略します。

### アダプターに与えるデータ
```kotlin
val fruitData = mutableListOf(
    Fruit("りんご","赤",100,1),
    Fruit("りんご","青",110,2),
    Fruit("みかん","オレンジ",70,3),
    Fruit("ぶどう","紫",200,4)
)
```
### メインアクティビティー
```kotlin
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //viewを読み込む
        val textview = findViewById<AutoCompleteTextView>(R.id.autoCompleteTextView)

        //アダプターの作成
        val fruitAdapter = FruitAdapter(this,android.R.layout.simple_spinner_dropdown_item,fruitData)
        //アダプターのセット
        textview.setAdapter(fruitAdapter)
        //1文字入力で候補出すように変更
        textview.threshold = 1
        //タップされた時の処理を変更
        textview.setOnItemClickListener { parent, _, position, id ->
            val selectedFruit = parent.adapter.getItem(position) as Fruit?
            textview.setText(selectedFruit?.name)
        }
    }
}
```
`ArrayAdapter`と違いタップされた時の挙動を変更しています。注意してください。
## 完成したもの
一応貼っときます。
動作確認程度のものなのでお粗末なのは許してください。
![無題88_20220323214828.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2581152/891865e9-d4b6-12a0-f3d2-594cb5053767.png)

## 最後に
ミスがあればコメントお願いしまず。