Reputation: 1541
I trying filtering recycler view with filter function in adapter but it's not working.
I have added searchview listener like this :
init(){
binding.svCategory.setOnQueryTextListener(this)
}
override fun onQueryTextSubmit(query: String?): Boolean {
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
adapterCategories.getFilter().filter(newText)
return true
}
and here is my adapter that i have created :
class CategoriesAdapter(
var context: Context,
var listCategories: ArrayList<Categories>,
var onGalleryClick: (Any) -> Unit,
var onCameraClick: (Any) -> Unit,
var onDeleteClick: (Any) -> Unit
) :
RecyclerView.Adapter<CategoriesAdapter.CategoriesViewHolder>(), Filterable {
private var filterList: ArrayList<Categories> = listCategories
init {
filterList = listCategories
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): CategoriesViewHolder {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.rv_category_item, viewGroup, false)
return CategoriesViewHolder(view)
}
override fun onBindViewHolder(holder: CategoriesViewHolder, position: Int) {
holder.tvCategoryName.text = listCategories[position].name
if (listCategories[position].imageUri != null) {
Glide
.with(context)
.load(Uri.parse(listCategories[position].imageUri))
.centerCrop()
.placeholder(R.drawable.add)
.into(holder.ivImage)
}
if (listCategories[position].imageUri.isNullOrEmpty()) {
holder.ivDelete.visibility = View.GONE
} else {
holder.ivDelete.visibility = View.VISIBLE
}
holder.ivGallery.setOnClickListener {
onGalleryClick(position)
}
holder.ivCamera.setOnClickListener {
onCameraClick(position)
}
holder.ivDelete.setOnClickListener {
onDeleteClick(position)
}
}
override fun getItemCount(): Int {
return filterList.size
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val charSearch = constraint.toString()
filterList = if (charSearch.isEmpty()) {
listCategories
} else {
val resultList = ArrayList<Categories>()
for (row in listCategories) {
if (row.name.toLowerCase().contains(constraint.toString().toLowerCase())) {
resultList.add(row)
}
}
resultList
}
val filterResults = FilterResults()
filterResults.values = filterList
return filterResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
filterList = results?.values as ArrayList<Categories>
notifyDataSetChanged()
}
}
}
class CategoriesViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var tvCategoryName: AppCompatTextView = view.findViewById(R.id.tvCategoryName)
var ivImage: AppCompatImageView = view.findViewById(R.id.ivImage)
var ivGallery: AppCompatImageView = view.findViewById(R.id.ivGallery)
var ivCamera: AppCompatImageView = view.findViewById(R.id.ivCamera)
var ivDelete: AppCompatImageView = view.findViewById(R.id.ivDelete)
}
}
but it doesn't filter item properly, it shows the right count but doesn't show proper items in the recyclerview,
So what to do for this issue? Can anyone help?
Thanks in advance.
Upvotes: 1
Views: 811
Reputation: 19223
inside onBindViewHolder
you are using listCategories[position]
instead of filterList[position]
. on start it have same content like original listCategories
(init{}
call), but after filtering getItemCount
returns size of filtered results, but in onBindViewHolder
still drawing listCategories
array. work only on filterList
and keep listCategories
untouched, usable only on start (filling filterList
) and when restoring original list (e.g. when query removed)
PS. work only on some temporary array inside performFiltering
, currently you are changing filterList
strictly in line filterList = if
. just add var
before filterList
. this will make this array only locally available, it will be attached to filterResults.values
and then updated in publishResults
(these functions are called in different Thread
s)
Upvotes: 2