0

I have a custom adapter, and filter that I am currently implementing to filter a recycler view based on a simple substring search on my recycler view entries. Here is my adapter NotifyChanged() function, which updates the RecylerView, and my custom filter() function. Everything works great, except for the auto scrolling afterwards.

private fun notifyChanged() {
    val result = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
        override fun getOldListSize(): Int {
            return objects.size
        }

        override fun getNewListSize(): Int {
            return temp.size
        }

        override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            return this@DiffRecyclerViewAdapter.areItemsTheSame(objects[oldItemPosition], temp[newItemPosition])
        }

        override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            return this@DiffRecyclerViewAdapter.areContentsTheSame(objects[oldItemPosition], temp[newItemPosition])
        }
    })
    objects.clear()
    objects.addAll(temp)

    result.dispatchUpdatesTo(this)
}


fun filter(text : String){

    val ob = original_objects as ArrayList<Category>
    val filtered_categories = ArrayList<T>() as ArrayList<Category>


    for (category in ob){
        //val temp_category = category
        val list_of_subcategories = ArrayList<T>() as ArrayList<Category>
        for (subcategory in category.categories){
            val name_of_category = subcategory.name.toLowerCase()
            if (name_of_category.contains(text)){
                list_of_subcategories?.add(subcategory)
            }
        }
        if (list_of_subcategories.size > 0){
            val newCategory = Category(category.id,category.name,category.description,category.videos,list_of_subcategories)
            filtered_categories.add(newCategory)
        }
    }
    temp = filtered_categories as MutableList<T>
    notifyChanged()
}

In my SearchActivity.kt I have the following listener:

    searchEditText.addTextChangedListener(object : TextWatcher{
        override fun afterTextChanged(s: Editable?) {}

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            adapter.filter(s.toString())
            recyclerView.scrollToPosition(0)
        }

    })

I was looking through the source code of DiffUtil and notifyDataSetChanged() to see how scrolling after filtering works. But didn't have much luck. The whole problem is that after I search text the RecyclerView is filtered fine. But will scroll to inconsistent locations. I want it to scroll back to the top every single time, but this isn't happening. EVEN WITH scrollToPosition(0) it will USUALLY scroll to the top, but not always.

I thought scrolling to the top was typically automatic in this case. I'm curious as to what the best practice is in updating and scrolling.

dougie
  • 53
  • 8

1 Answers1

1

It needs some time to update the data on recyclerview. Mean while you are trying to scroll which doesn't work in most of the cases. PReferably use a postDelayed with 200 or 300 milliseconds before scrolling

Ex:

new Handler.postDelayed(new Runnable(){
                @Override
                public void run(){
            recyclerView.scrollToPosition(0)
                 }
            }, 300);
Viswanath Kumar Sandu
  • 2,230
  • 2
  • 17
  • 34
  • Awesome, it works. I'm curious though if there's a way to do this without needing to specify a delay time. I could imagine with big lists this could potentially take longer than 300 ms. Is there another standard way to scroll to the top? – dougie Sep 12 '18 at 05:38
  • You can check position value in onBindViewHolder if it is the last value of array list then you can call recyclerView.scrollToPosition(0). – Parvesh Khan Sep 12 '18 at 05:44
  • @dougie As the solution worked for you, could you give upvote and mark the answer as right. Even if the data size is huge, there won't be much difference in applying it on recyclerview. So 300 milli seconds would ideally work in almost all cases – Viswanath Kumar Sandu Sep 12 '18 at 14:38
  • After trying this solution, I found [that one](https://stackoverflow.com/a/32679359/4917907) which in my opinion provides a much smoother result. – Ronan Mar 14 '19 at 23:46