I would use a SearchView to filter my RecyclerView, on stackoverflow and other sites i've found just examples of using Filterable with Java and with RecyclerView.Adapter while i'm using ListAdapter..
So i was trying to make the custom filter by my self but when i try to filter the adapter i just get a null on my MutableList in publishResults.
My Adapter code looks like this:
class ArticoliListAdapter : ListAdapter<Articolo, ArticoliListAdapter.ArticoliViewHolder>(ArticoliComparator()), Filterable {
private val list = mutableListOf<Articolo>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticoliViewHolder {
return ArticoliViewHolder.create(parent)
}
override fun onBindViewHolder(holder: ArticoliViewHolder, position: Int) {
val current = getItem(position)
holder.bind(current)
}
override fun getItemId(position: Int): Long {
val articolo = currentList[position]
return articolo.barcode.hashCode().toLong()
}
class ArticoliViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val barcode: TextView = itemView.findViewById(R.id.barcode)
private val qta: TextView = itemView.findViewById(R.id.qta)
private val desc: TextView = itemView.findViewById(R.id.desc)
private val um: TextView = itemView.findViewById(R.id.um)
fun bind(articolo: Articolo?) {
barcode.text = articolo?.barcode
qta.text = articolo?.qta?.formatForQta()
um.text = articolo?.um?.toLowerCase(Locale.ITALIAN)
desc.text = if(articolo?.desc.isNullOrEmpty()) "-" else articolo?.desc
}
private fun Float.formatForQta(): String {
val floatString = this.toString()
val decimalString: String = floatString.substring(floatString.indexOf('.') + 1, floatString.length)
return when (decimalString.toInt() == 0) {
true -> this.toInt().toString()
false -> "%.3f".format(this)
}
}
companion object {
fun create(parent: ViewGroup): ArticoliViewHolder {
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.item_layout, parent, false)
return ArticoliViewHolder(view)
}
}
}
class ArticoliComparator : DiffUtil.ItemCallback<Articolo>() {
override fun areItemsTheSame(oldItem: Articolo, newItem: Articolo): Boolean {
return oldItem === newItem
}
override fun areContentsTheSame(oldItem: Articolo, newItem: Articolo): Boolean {
return oldItem.qta == newItem.qta
}
}
override fun getFilter(): Filter {
return customFilter
}
private val customFilter = object: Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredList = mutableListOf<Articolo>()
if (constraint == null || constraint.isEmpty()){
filteredList.addAll(currentList)
}else {
val filterPattern = constraint.toString().toLowerCase(Locale.ITALIAN).trim { it <= ' ' }
for (item in currentList) {
if (item.barcode.toLowerCase(Locale.ITALIAN).contains(filterPattern) || item.desc?.toLowerCase(
Locale.ITALIAN
)!!.contains(filterPattern)) {
filteredList.add(item)
}
}
}
val results = FilterResults()
results.values = filteredList
return results
}
override fun publishResults(constraint: CharSequence?, filterResults: FilterResults?) {
list.clear()
list.addAll(filterResults?.values as MutableList<Articolo>)
notifyDataSetChanged()
}
}
}
So i was wondering which would be the right way to built a custom filter to filter my data in the recyclerView by using ListAdapter in Kotlin.
I'm calling the filter in my fragment like this:
override fun onQueryTextChange(query: String?): Boolean {
adapter.filter.filter(query)
return false
}
But when i try to filter nothing happend and still all items are shown...
Data to the RecyclerView adapter is set from my ViewHolder and the data is get from the DataBase (LiveData<List<Articolo>>)
Here is the code from my Fragment:
articoliViewModel.articoli.observe(viewLifecycleOwner) { articoli ->
articoli.let { adapter.submitList(it) }
}