I'm referring to this tutorial.
Everything runs fine without error but its not filtering
when I type anything. It is not filtering the list.
I don't know what I'm doing wrong.
The following is my adapter and activity code.
Adapter code
class Table_Adapter(val context: Context) : RecyclerView.Adapter<Table_Adapter.MyViewHolder>(),Filterable {
var mFilteredList: MutableList<Tabledata> = mutableListOf()
var Tablelist: MutableList<Tabledata> = mutableListOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(
R.layout.table_recycle_item,
parent,
false
)
return MyViewHolder(view)
}
override fun getItemCount(): Int {
return Tablelist.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.productname.text = Tablelist.get(position).name
holder.producername.text = Tablelist.get(position).producer
holder.productprice.text = Tablelist.get(position).cost.toString()
Glide.with(context).load(Tablelist.get(position).product_images)
.into(holder.image)
holder.rate.setRating(Tablelist.get(position).rating.toFloat());
holder.itemView!!.setOnClickListener {
val context:Context=holder.itemView.context
val i=Intent(
context,
Product_details::class.java
)
i.putExtra("id", Tablelist.get(position).id.toString())
i.putExtra("image", Tablelist.get(position).product_images)
context.startActivity(i)
}
}
fun setMovieListItems(movieList: MutableList<Tabledata>){
this.Tablelist = movieList;
notifyDataSetChanged()
}
class MyViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView!!) {
val productname: TextView = itemView!!.findViewById(R.id.title)
val producername: TextView = itemView!!.findViewById(R.id.title1)
val productprice: TextView = itemView!!.findViewById(R.id.title2)
val rate: RatingBar=itemView!!.findViewById(R.id.ratingbar)
val image: ImageView = itemView!!.findViewById(R.id.image)
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults? {
val charString = charSequence.toString()
if (charString.isEmpty()) {
mFilteredList = Tablelist
} else {
val filteredList: MutableList<Tabledata> = ArrayList()
for (androidVersion in Tablelist) {
/* if (androidVersion.name.toLowerCase()
.contains(charString)
) {
filteredList.add(androidVersion)
}*/
if (androidVersion.name.toLowerCase()
.contains(charString.toLowerCase()) || androidVersion.name
.contains(charSequence)
) {
filteredList.add(androidVersion)
}
}
mFilteredList = filteredList
}
val filterResults = FilterResults()
filterResults.values = mFilteredList
return filterResults
}
override fun publishResults(charSequence: CharSequence?, filterResults: FilterResults) {
mFilteredList = filterResults.values as MutableList<Tabledata>
notifyDataSetChanged()
}
}
}
}
Activity:
class Tables : AppCompatActivity() {
lateinit var recyclerView: RecyclerView
lateinit var recyclerAdapter: Table_Adapter
var Tablelist : MutableList<Tabledata> = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.table_activity)
var mActionBarToolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbartable);
setSupportActionBar(mActionBarToolbar);
if (getSupportActionBar() != null){
getSupportActionBar()?.setDisplayHomeAsUpEnabled(true);
getSupportActionBar()?.setDisplayShowHomeEnabled(true);
getSupportActionBar()?.setHomeAsUpIndicator(R.drawable.ic_keyboard_arrow_left_black_24dp);
getSupportActionBar()?.setTitle((Html.fromHtml("<font color=\"#FFFFFF\">" + getString(R.string.Tables) + "</font>")));
}
recyclerView = findViewById(R.id.recyleview)
recyclerAdapter = Table_Adapter(this)
recyleview.layoutManager = LinearLayoutManager(this)
recyclerView.addItemDecoration(
DividerItemDecoration(
recyclerView.context,
DividerItemDecoration.VERTICAL
)
)
recyleview.adapter = recyclerAdapter
RetrofitClient.instancetable.getAllPhotos(product_category_id = "1", value = 1).enqueue(
object : Callback<Table_response> {
override fun onFailure(call: Call<Table_response>, t: Throwable) {
Toast.makeText(applicationContext, "falied", Toast.LENGTH_LONG).show()
}
override fun onResponse(
call: Call<Table_response>,
response: Response<Table_response>
) {
if (response?.body() != null) {
recyclerAdapter.setMovieListItems((response.body()?.data as MutableList<Tabledata>?)!!)
}
}
})
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
NavUtils.navigateUpFromSameTask(this)
true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
val search: MenuItem = menu.findItem(R.id.search)
val searchView: SearchView = MenuItemCompat.getActionView(search) as SearchView
search(searchView)
return true
}
override fun onBackPressed() {
super.onBackPressed()
}
private fun search(searchView: SearchView) {
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
recyclerAdapter.getFilter().filter(newText)
return true
}
})
}
}
Thanks in advance.
Search view queries do not result in a filtered list because you are not using the filtered list.
onBindViewHolder and getItemCount uses only Tablelist variable. mFilteredList only holds filtered results - not uses them.
Store original list as you do it currently, but replace the use of Tablelist with mFilteredList in onBindViewHolder and getItemCount. Also, a minor update in setMovieListItems is required. mFilteredList is also declared as unmutable. performFiltering also was improved a little bit and is not shorter. Everything is presented below:
class Table_Adapter() : RecyclerView.Adapter<Table_Adapter.MyViewHolder>(), Filterable {
var mFilteredList: List<Tabledata> = listOf()
var tableList: MutableList<Tabledata> = mutableListOf()
...
override fun getItemCount(): Int {
return mFilteredList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val tableItem = mFilteredList.get(position)
holder.productname.text = tableItem.name
holder.producername.text = tableItem.producer
holder.productprice.text = tableItem.cost.toString()
Glide.with(holder.itemView!!.context).load(tableItem.product_images)
.into(holder.image)
holder.rate.setRating(tableItem.rating.toFloat());
holder.itemView!!.setOnClickListener {
val context: Context = holder.itemView.context
val i = Intent(
context,
Product_details::class.java
)
i.putExtra("id", tableItem.id.toString())
i.putExtra("image", tableItem.product_images)
context.startActivity(i)
}
}
fun setMovieListItems(movieList: MutableList<Tabledata>) {
tableList = movieList.toMutableList() // makes a copy
mFilteredList = movieList
notifyDataSetChanged()
}
...
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults? {
val queryString = charSequence.toString()
val filterResults = FilterResults()
filterResults.values =
if (queryString.isEmpty()) {
tableList
} else {
tableList.filter {
it.name.contains(queryString, ignoreCase = true) || it.name.contains(charSequence)
}
}
return filterResults
}
override fun publishResults(charSequence: CharSequence?, filterResults: FilterResults) {
mFilteredList = filterResults.values
notifyDataSetChanged()
}
}
}
}
Related
I did my adapter and made a function that would filter my list. But the issue is that it's no showing the results and i don't know why. There 2 lists: one of them is full list and the other one is the filtered list. Here is my adapter:
class SearchAdapter : RecyclerView.Adapter<SearchViewHolder>(), Filterable {
var fullInstitutionData: ArrayList<InstitutionModel> = ArrayList()
var institutionData: ArrayList<InstitutionModel> = ArrayList()
init {
institutionData = ArrayList()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchViewHolder {
val inflater = LayoutInflater.from(parent.context)
return SearchViewHolder(inflater, parent)
}
override fun getItemCount(): Int = institutionData.size
override fun onBindViewHolder(holder: SearchViewHolder, position: Int) {
val dialogData: InstitutionModel = institutionData[position]
holder.bind(dialogData)
}
override fun getFilter(): Filter {
return customFilter
}
fun addDataFromClient(listDataClient: ArrayList<InstitutionModel>) {
institutionData.addAll(listDataClient)
fullInstitutionData = ArrayList(listDataClient)
notifyDataSetChanged()
}
private val customFilter = object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredList = arrayListOf<InstitutionModel>()
if (constraint == null || constraint.length == 0) {
filteredList.addAll(institutionData)
} else {
val filterPattern = constraint.toString().toLowerCase().trim()
for (item in fullInstitutionData) {
if (item.name.toLowerCase().contains(filterPattern) || item.name?.toLowerCase()!!
.contains(filterPattern)) {
filteredList.add(item)
}
}
}
val results = FilterResults()
results.values = filteredList
return results
}
override fun publishResults(constraint: CharSequence?, filterResults: FilterResults?) {
institutionData.clear()
institutionData.addAll(filterResults?.values as MutableList<InstitutionModel>)
}
}
}
And this is my search function that i did the setOnQueryListener in the my fragment:
fun searchInstitution() {
searchViewInstitutions.apply {
setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
searchAdapter.filter.filter(newText)
return false
}
})
}
}
This is the code when i call the recyclerview on onActivityCreated:
val llm = LinearLayoutManager(context)
llm.orientation = LinearLayoutManager.VERTICAL
rvSearch.layoutManager = llm
rvSearch.adapter = SearchAdapter()
searchAdapter.addDataFromClient(data)
searchInstitution()
There are two fixes needed:
notifyDataSetChanged() when you publishResults()
override fun publishResults(constraint: CharSequence?, filterResults: FilterResults?) {
institutionData.clear()
institutionData.addAll(filterResults?.values as MutableList<InstitutionModel>)
notifyDataSetChanged() // <<< Change Here
}
Add the full list when there is no match instead of the filtered one
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredList = arrayListOf<InstitutionModel>()
if (constraint == null || constraint.length == 0) {
filteredList.addAll(fullInstitutionData) // <<< Change Here
It is the main Activity code (EDITED)
Here I trying to add searchView and filter that recyclerView, but I am facing issue related to getfilter(). In MainActivity class > searchView.setOnQuery... > mAdapter.getFilter().filter(query).
May be I must be missing something or I have done something wrong.
class MainActivity : AppCompatActivity() {
var recyclerView: RecyclerView? = null
var mAdapter: RecyclerView.Adapter<*>? = null
var layoutManager: RecyclerView.LayoutManager? = null
var personUtilsList: MutableList<PersonUtils>? = null
var personUtils: PersonUtils? = null
var rq: RequestQueue? = null
var request_url = "https://sheetdb.io/api/v1/wgkdzpdiyflckl9"
private lateinit var adp: CustomRecyclerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
rq = Volley.newRequestQueue(this)
recyclerView = findViewById<View>(R.id.recycleViewContainer) as RecyclerView
recyclerView!!.setHasFixedSize(true)
layoutManager = LinearLayoutManager(this)
recyclerView!!.setHasFixedSize(true)
recyclerView!!.layoutManager = layoutManager
personUtilsList = java.util.ArrayList()
sendRequest()
search.addTextChangedListener {
//search is a editText
object : TextWatcher{
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
filterList(s.toString())
} } }
}
sendRequest{...}
private fun filterList(toString: String) {
var temp: MutableList<PersonUtils> = ArrayList()
for (data in personUtilsList!!){
if(data.personFirstName!!.contains(toString.capitalize())
){
temp.add(data)
}
}
adp.updateList(temp)
}
}
It is adapter Class (EDITED)
public class CustomRecyclerAdapter(private val context: Context, personUtils: List<PersonUtils>)
: RecyclerView.Adapter<CustomRecyclerAdapter.ViewHolder>(), Filterable {
private var personUtils: MutableList<PersonUtils>
private var utilsFilterList: MutableList<PersonUtils>
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.single_list_item, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemView.tag = personUtils[position]
val pu = personUtils[position]
holder.pName.text = pu.personFirstName.toString() + " .58-" + pu.personLastName.toString()
holder.pJobProfile.text = pu.jobProfile
holder.Department.text = pu.Department
holder.email.text = pu.Email
holder.phN.text = pu.PhoneNo
Glide.with(this.context).load(pu.imgUrl.toString()).into(holder.img!!)
}
fun updateList(temp : MutableList<PersonUtils>){
personUtils = temp
notifyDataSetChanged()
}
override fun getItemCount(): Int {
return personUtils.size
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var pName: TextView
var pJobProfile: TextView
var Department: TextView
var email: TextView
var phN: TextView
var img: ImageView? = null
init {
pName = itemView.findViewById<View>(R.id.pNametxt) as TextView
pJobProfile = itemView.findViewById<View>(R.id.pJobProfiletxt) as TextView
Department = itemView.findViewById<View>(R.id.department_Branch) as TextView
email = itemView.findViewById<View>(R.id.user_email) as TextView
phN = itemView.findViewById<View>(R.id.user_phNo) as TextView
img = itemView.findViewById<View>(R.id.userImg) as ImageView
itemView.setOnClickListener { view ->
val cpu = view.tag as PersonUtils
Toast.makeText(view.context,
"Copied to clipboard", Toast.LENGTH_SHORT).show()
val Clipboard = view.context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val myClip = ClipData.newPlainText(cpu.personFirstName, cpu.personFirstName)
Clipboard.setPrimaryClip(myClip)
}
}
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
var charString = constraint.toString()
var filteredList : MutableList<PersonUtils> = mutableListOf()
if (charString.isEmpty()) {
filteredList.addAll(utilsFilterList)
} else {
val filteredList: MutableList<PersonUtils> = ArrayList()
for (row in personUtils) {
if (row.personFirstName!!.toLowerCase().contains(charString.toLowerCase())
|| row.Department!!.contains(constraint.toString())) {
filteredList.add(row)
}
}
utilsFilterList = filteredList
}
val filterResults = FilterResults()
filterResults.values = utilsFilterList
return filterResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
if(results !=null) {
personUtils.clear()
personUtils.addAll(results.values as Collection<PersonUtils>)
notifyDataSetChanged()
}
}
}
}
init {
this.personUtils = personUtils as MutableList<PersonUtils>
utilsFilterList = personUtils.toMutableList()
}
}
You are using utilsFilterList to filter the Recyclerview items but you are returning personUtils.size from getItemCount()
So even if you call notifyDataSetChanged() in publishResults() , your main list personUtils remains same because you are storing all filtered results in utilsFilterList
Edit :
I usually use the below approach
Marked Edits within **
public class CustomRecyclerAdapter(private val context: Context, personUtils: List) : RecyclerView.Adapter<CustomRecyclerAdapter.ViewHolder>(), Filterable {
private var personUtils: MutableList<PersonUtils>
*private var utilsFilterList : MutableList<PersonUtils> *
override fun getFilter(): Filter {
return object : Filter()
{
override fun performFiltering(constraint: CharSequence?): FilterResults {
var charString = constraint.toString()
*val filteredList: MutableList<PersonUtils> = mutableListOf()*
if(charString.isEmpty()){
*filteredList.addAll(utilsFilterList)*
}
else{
for(row in utilsFilterList){
if (row.personFirstName!!.toLowerCase().contains(charString.toLowerCase())
|| row.Department!!.contains(constraint.toString())) {
filteredList.add(row)
}
}
}
val filterResults = FilterResults()
filterResults.values = filteredList
return filterResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
*if(results !=null) {
personUtils.clear()
personUtils.addAll(results.values as Collection<PersonUtils>)*
notifyDataSetChanged()
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.single_list_item, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemView.tag = personUtils[position]
val pu = personUtils[position]
holder.pName.text = pu.personFirstName.toString() + " .58-" +
pu.personLastName.toString()
holder.pJobProfile.text = pu.jobProfile
holder.Department.text = pu.Department
holder.email.text = pu.Email
holder.phN.text = pu.PhoneNo
Glide.with(this.context).load(pu.imgUrl.toString()).into(holder.img!!)
}
override fun getItemCount(): Int {
return personUtils.size
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var pName: TextView
var pJobProfile: TextView
var Department: TextView
var email: TextView
var phN: TextView
var img : ImageView? = null
init {
pName = itemView.findViewById<View>(R.id.pNametxt) as TextView
pJobProfile = itemView.findViewById<View>(R.id.pJobProfiletxt) as TextView
Department = itemView.findViewById<View>(R.id.department_Branch) as TextView
email = itemView.findViewById<View>(R.id.user_email) as TextView
phN = itemView.findViewById<View>(R.id.user_phNo) as TextView
img = itemView.findViewById<View>(R.id.userImg) as ImageView
itemView.setOnClickListener { view ->
val cpu = view.tag as PersonUtils
Toast.makeText(view.context,
"Copied to clipboard", Toast.LENGTH_SHORT).show()
val Clipboard = view.context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val myClip = ClipData.newPlainText(cpu.personFirstName, cpu.personFirstName)
Clipboard.setPrimaryClip(myClip)
}
}
}
init {
this.personUtils = personUtils as MutableList<PersonUtils>
*utilsFilterList = personUtils.toMutableList()*
}
}
I am using following library to animate items in my recyclerview on removal
https://github.com/wasabeef/recyclerview-animators
I am trying to apply slide to right animation to only removed item but for some reason all items in recyclerview disappears first and then animated back to their position strangely.
Please watch the following video.
Here is my code its very simple:
friends_screen_friendlist_recyclerview.itemAnimator = SlideInRightAnimator()
friends_screen_friendlist_recyclerview.itemAnimator?.apply {
addDuration = 120;
removeDuration = 1000;
moveDuration = 500;
changeDuration = 500;
}
friendItems.removeAt(0)
friends_screen_friendlist_recyclerview.adapter!!.notifyItemRemoved(0)
Adapter class:
class FriendListAdapter(val items : ArrayList<FriendListItem>, val context: Context,val listener:FriendListListener) : androidx.recyclerview.widget.RecyclerView.Adapter<FriendListViewHolder>(),Filterable {
var filterItems = ArrayList<FriendListItem>()
init{
filterItems = items
}
// Gets the number of animals in the list
override fun getItemCount(): Int {
return filterItems.size
}
override fun getItemViewType(position: Int): Int {
return position
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val charSearch = constraint.toString()
if (charSearch.isEmpty()) {
filterItems = items
} else {
val resultList = ArrayList<FriendListItem>()
for (row in items) {
if (row.userName.toLowerCase(Locale.ROOT).contains(charSearch.toLowerCase(Locale.ROOT))) {
resultList.add(row)
}
}
filterItems = resultList
}
val filterResults = FilterResults()
filterResults.values = filterItems
return filterResults
}
#Suppress("UNCHECKED_CAST")
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
filterItems = results?.values as ArrayList<FriendListItem>
notifyDataSetChanged()
}
}
}
// Inflates the item views
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FriendListViewHolder {
return FriendListViewHolder(LayoutInflater.from(context).inflate(R.layout.friendlist_item, parent, false))
}
// Binds each animal in the ArrayList to a view
override fun onBindViewHolder(holder: FriendListViewHolder, position: Int) {
//holder?.profileImage?.background = items[position].profileImage
holder?.userName?.text = filterItems[position].userName
holder?.level?.text = "Seviye "+filterItems[position].level
// do the necessary profilePic checks.
Picasso.get().load(filterItems[position].profileImage).into(holder?.profileImage, object : Callback {
override fun onSuccess() {
listener.onProfilePicLoaded()
}
override fun onError(e: Exception?) {
listener.onProfilePicLoaded() // error but anyway. just tell messages class its loaded so it can show the page.
}
})
if(filterItems[position].gender == 0){
holder?.gender?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.male_icon))
}else{
holder?.gender?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.female_icon))
}
if(filterItems[position].isOnline){
holder?.isOnline?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.online_circle))
}else{
holder?.isOnline?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.offline_circle))
}
holder.itemContainer.setOnClickListener {
listener.onFriendSelected(filterItems[position])
}
holder.itemContainer.setOnLongClickListener {
listener.onFriendSelectedAndHolded(filterItems[position],position)
Log.d("yunusdebug","long")
return#setOnLongClickListener true
}
}
}
class FriendListViewHolder (view: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(view) {
// Holds the TextView that will add each animal to
val itemContainer = view.friendlist_item_container
val userName = view.friendlist_item_username_textview
val level = view.friendlist_item_level_textview
val isOnline = view.friendlist_item_isOnline
val profileImage = view.friendlist_item_profile_image
val gender = view.friendlist_item_gender
}
When you remove an item in your adapter you should also notify the new range. Please try the following:
friendItems.removeAt(index)
notifyItemRemoved(index)
notifyItemRangeChanged(index,friendItems.size)
I have implemented searchView with recyclerView it is not working and giving errors I did not understand where I am making mistakes. below my MainActivity where I have implemented searchview logic
I have implemented searchView with recyclerView it is not working and giving errors I did not understand where I am making mistakes. below my MainActivity where I have implemented searchview logic
class MemberActivity : AppCompatActivity() {
private var memberAdapter: MemberAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_member)
val compositeDisposable = CompositeDisposable()
compositeDisposable.add(
ServiceBuilder.buildService(SpectrumInterface::class.java)
.getMembers()
.toObservable()
.flatMap { Observable.fromIterable(it) }
.flatMap { Observable.fromIterable(it.members) }
.toList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ members -> onResponse(members) },
{ t -> onFailure(t) })
)
memberAdapter = MemberAdapter()
recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayout.VERTICAL))
private fun onFailure(t: Throwable) {
Toast.makeText(this, t.message, Toast.LENGTH_SHORT).show()
}
private fun onResponse(members: List<Member>) {
progressBar.visibility = View.GONE
(recyclerView.adapter as MemberAdapter).setMembers(members)
}
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
memberAdapter?.getFilter()?.filter(newText)
return true
}
ascendingButton.setOnClickListener
{
memberAdapter?.sortAscending()
}
descendingButton.setOnClickListener {
memberAdapter?.sortDescending()
}
}
}
below my Adapter where I have implemented filter logic
class MemberAdapter : RecyclerView.Adapter<MemberAdapter.MemberViewHolder>() {
private val members = mutableListOf<Member>()
fun setMembers(data: List<Member>) {
members.clear()
members.addAll(data)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MemberViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.member_list, parent, false)
return MemberViewHolder(view)
}
override fun getItemCount() = members.size
fun sortAscending() {
members.sortBy { it.age }
notifyDataSetChanged()
}
fun sortDescending() {
members.sortByDescending { it.age }
notifyDataSetChanged()
}
fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults {
val query = charSequence.toString()
val filtered: MutableList<Member> = ArrayList()
if (query.isEmpty()) {
filtered.clear()
filtered.addAll(members)
} else {
filtered.addAll(members.filter {
it.id.toLowerCase(Locale.ROOT)
.contains(query.toLowerCase(Locale.ROOT)) || it.age.toString()
.contains(query)
})
}
val results = FilterResults()
results.count = filtered.size
results.values = filtered
return results
}
override fun publishResults(charSequence: CharSequence, results: FilterResults) {
members.clear()
members.addAll(results.values as Collection<Member>)
notifyDataSetChanged()
}
}
}
override fun onBindViewHolder(holder: MemberViewHolder, position: Int) {
return holder.bind(members[position])
}
class MemberViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val memberAge: TextView = itemView.findViewById(R.id.memberAge)
// private val memberName: TextView = itemView.findViewById(R.id.memberName)
private val lastName: TextView = itemView.findViewById(R.id.lastName)
private val firstName: TextView = itemView.findViewById(R.id.firstName)
private val emailAddress: TextView = itemView.findViewById(R.id.emailAddress)
private val phone: TextView = itemView.findViewById(R.id.phone)
fun bind(member: Member) {
memberAge.text = member.age.toString()
lastName.text = member.name?.last
firstName.text = member.name?.first
emailAddress.text = member.email
phone.text = member.phone
}
}
}
Your mistake is updating members and then using it again as your base for future filtering.
Instead:
Create another list filteredMembers in MembersAdapter, initialize it to be equal to members in setMembers()
Make MembersAdapter reflect the items in filteredMembers
override fun getItemCount() = filteredMembers.size
override fun onBindViewHolder(holder: MemberViewHolder, position: Int) {
return holder.bind(filteredMembers[position])
}
Make your filter update filteredMembers and not members
all element are responsible for the search worked normal. the list just does not want to change. maybe someone know how this work i searched some information on internet but alas not found
Main Activity
class MainActivity : AppCompatActivity() {
var searchView:SearchView?=null
lateinit var adapter: ProductListAdapter
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.menu_item_list, menu)
adapter = ProductListAdapter(applicationContext)
val searchManager = getSystemService(Context.SEARCH_SERVICE)as SearchManager
searchView = menu!!.findItem(R.id.action_search).actionView as SearchView
searchView!!.setSearchableInfo(searchManager.getSearchableInfo(componentName))
searchView!!.maxWidth = Int.MAX_VALUE
searchView!!.setOnQueryTextListener(object:SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
adapter.filter.filter(query)
Toast.makeText(this#MainActivity,"Work onQueryTextSubmit",Toast.LENGTH_SHORT).show()
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
adapter.filter.filter(newText)
Toast.makeText(this#MainActivity,"onQueryTextChange",Toast.LENGTH_SHORT).show()
return true
}
})
return super.onCreateOptionsMenu(menu)
}
}
maybe i have problem in adapter of recycler view i dont understand
i think i have problem with filterListAdapter list because in my example they are emptylist?
Adapter
class ProductListAdapter internal constructor(
context: Context
) : RecyclerView.Adapter<ProductListAdapter.ProductViewHolder>(), Filterable {
private val inflater: LayoutInflater = LayoutInflater.from(context)
private var productsList = emptyList<ProductEntity>()
internal var filterListResult: List<ProductEntity>
init {
this.filterListResult = productsList
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val charSearch = constraint.toString()
if (charSearch.isEmpty())
filterListResult = productsList
else {
val resultList = ArrayList<ProductEntity>()
for(row in productsList){
if (row.productName!!.toLowerCase().contains(charSearch.toLowerCase()))
resultList.add(row)
}
filterListResult = resultList
}
val filterResults = FilterResults()
filterResults.values = filterListResult
return filterResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
filterListResult = results!!.values as List<ProductEntity>
notifyDataSetChanged()
}
}
}
override fun getItemCount(): Int {
var sizes = filterListResult.size
return sizes
}
override fun onBindViewHolder(holder: ProductViewHolder, position: Int)
{
holder.onBind(productsList[position])
holder.onBind(filterListResult[position])
}
class ProductViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val productName = view.product_name
private val productPrice = view.product_price
private val productWeight = view.product_weight
fun onBind(productEntity: ProductEntity) {
productName.text = productEntity.productName
productPrice.text = productEntity.productPrice.toString()
productWeight.text = productEntity.productWeight.toString()
}
}
internal fun setAll(productEntity: List<ProductEntity>) {
this.productsList = productEntity
this.filterListResult = productEntity
notifyDataSetChanged()
}
}