2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-03-25

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

目次

1.今回扱うデータクラス
2.アダプターの作成
3.実際に使う
4.完成したもの
5.最後に

今回使うデータクラス

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{
        //中身は以下
        }

継承関係です。allItemsMutableListで作成しました。配列やコレクションだったらなんでもいいはずです。勿論それによってコードは変わっていきます。


Filterable
private var mutableAllItems:MutableList<Fruit> = allItems

フィルターで絞り込んでいくときに使われる変数です。


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

絞り込まれた要素数を返します。


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

1列分のデータを返します。
アダプター作成時に定義したデータ型を返す必要があります。


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

idを自分で決めるならオーバーライドします。
オーバーライドしなくても動きます。


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なので綺麗に表示されます。


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

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


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はフィルターされたリストが入っていて、これをアダプター全体と共有します。


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置いただけなので省略します。

アダプターに与えるデータ

val fruitData = mutableListOf(
    Fruit("りんご","赤",100,1),
    Fruit("りんご","青",110,2),
    Fruit("みかん","オレンジ",70,3),
    Fruit("ぶどう","紫",200,4)
)

メインアクティビティー

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

最後に

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

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?