ArrayAdapterをカスタムして自作のデータクラスを渡します。
AutoCompleteTextView
のフィルターをカスタマイズしようとしたところ思ったより多くの情報が得られたのでまとめました。
フィルターをカスタマイズしただけの記事も書きます。
目次
1.今回扱うデータクラス
2.アダプターの作成
3.実際に使う
4.完成したもの
5.最後に
今回使うデータクラス
data class Fruit(
val name:String,
val color:String,
val price:Int,
val id:Int)
Adapterを作る
Adapterのコード全文です。コードだけでいい人はどうぞ。
下で解説しています。
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
}
}
}
}
class SampleAdapter(context: Context, @LayoutRes private val layoutResource: Int, private val allItems: MutableList<Fruit>):
ArrayAdapter<Fruit>(context,layoutResource,allItems),
Filterable{
//中身は以下
}
継承関係です。allItems
はMutableList
で作成しました。配列やコレクションだったらなんでもいいはずです。勿論それによってコードは変わっていきます。
private var mutableAllItems:MutableList<Fruit> = allItems
フィルターで絞り込んでいくときに使われる変数です。
override fun getCount(): Int {
return mutableAllItems.size
}
絞り込まれた要素数を返します。
override fun getItem(position: Int): Fruit? {
return mutableAllItems[position]
}
1列分のデータを返します。
アダプター作成時に定義したデータ型を返す必要があります。
override fun getItemId(position: Int): Long {
return mutableAllItems[position].id.toLong()
}
idを自分で決めるならオーバーライドします。
オーバーライドしなくても動きます。
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
なので綺麗に表示されます。
override fun getFilter(): Filter {
return object: Filter(){
//中身は以下
}
}
配列の要素を変えたのとフィルターも作り直す必要があります。
フィルターを呼び出さない用途なら必要ないかもしれません。
この中でpublisResults
とperformFiltering
をオーバーライドする必要があります。
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
はフィルターされたリストが入っていて、これをアダプター全体と共有します。
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
と違いタップされた時の挙動を変更しています。注意してください。
完成したもの
一応貼っときます。
動作確認程度のものなのでお粗末なのは許してください。
最後に
ミスがあればコメントお願いしまず。