Reputation: 63
I'm trying to filter a recyclerList
that contains around 3000 items.
My filter kinda works but for some reason it doesn't update the list until I scroll far enough.
For example: the top 2 elements start with the letter A --> if my filter starts with B, the top 2 elements still get shown until I scroll far enough so that they are no longer visible. When I scroll back up, they disappeared from the view.
Adapter
class LocationAdapter(
private var locations: ArrayList<Costcenter>,
private val onLocationClick: (location: Costcenter) -> Unit
) : RecyclerView.Adapter<LocationAdapter.LocationViewHolder>(), Filterable {
var locationsFiltered = locations
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LocationViewHolder {
val view = LayoutInflater
.from(parent.context)
.inflate(R.layout.location_row, parent, false)
return LocationViewHolder(view)
}
override fun getItemCount(): Int = locationsFiltered.size
override fun onBindViewHolder(holder: LocationViewHolder, position: Int) {
holder.bind(locationsFiltered[position])
}
inner class LocationViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val title: TextView = itemView.findViewById(R.id.txtCostCenter)
private val desc: TextView = itemView.findViewById(R.id.txtCostCenterDescription)
fun bind(loc: Costcenter) {
title.text = loc.goederenontvanger
desc.text = loc.goederenontvanger_omschrijving
itemView.setOnClickListener {
onLocationClick.invoke(loc)
}
}
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val charSearch = constraint.toString()
locationsFiltered = if (charSearch.isEmpty()) {
locations
} else {
val resultList = ArrayList<Costcenter>()
for (row in locations) {
if (row.goederenontvanger.toLowerCase()
.contains(charSearch.toLowerCase()) || row.goederenontvanger_omschrijving.toLowerCase()
.contains(charSearch.toLowerCase())
) {
resultList.add(row)
}
}
resultList
}
val filterResults = FilterResults()
filterResults.values = locationsFiltered
return filterResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
}
}
}
}
Fragment where the recyclerview gets created
class LocationsFragment : Fragment() {
private lateinit var locationAdapter: LocationAdapter
private val storageViewModel by activityViewModels<StorageViewModel>()
private lateinit var currentView : View
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
var view = inflater.inflate(R.layout.fragment_locations, container, false)
var recycler = view.findViewById<RecyclerView>(R.id.recyclerLocations)
var filter = view.findViewById<SearchView>(R.id.editFilter)
locationAdapter = LocationAdapter(Utilities.costcenters) { loc -> setSelectedLocation(loc) }
val recycleMngr: RecyclerView.LayoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
filter.setOnQueryTextListener(object: SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
locationAdapter.filter.filter(newText)
return false
}
})
recycler.layoutManager = recycleMngr
recycler.adapter = locationAdapter
currentView = view
return view
}
Upvotes: 1
Views: 768
Reputation: 40840
You need to update the original list locationsFiltered
with the filtered results when the filter is published with publishResults()
and then notifyDataSetChanged()
to apply the changes on the RecyclerView
So add the below in publishResults()
method:
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
locationsFiltered = filterResults.values as ArrayList<Costcenter>
notifyDataSetChanged()
}
Upvotes: 1