Karan Mehta
Karan Mehta

Reputation: 1541

Recyclerview Filter not working in kotlin android

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

Answers (1)

snachmsm
snachmsm

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 Threads)

Upvotes: 2

Related Questions