2

I'm developing a application that the RecyclerView load new data when the user hit the bottom of the scroll. However, the list is already completed and have it's fixed size, I just want to put the content in the Recycler, but when I insert the content in the Recycler, the scroll returns to the top of the list. And then I need to scroll down all over again until I reach the new data that was inserted in to the bottom of the list. All that I want is to maintain the scroll position when the new data is loaded.

I've tried use descendantFocusability = "blocksDescendants", but this didn't work.

This is my XML code where the RecyclerView can be found

<?xmlversion="1.0"encoding="utf-8"?>

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:headerLayout="@layout/top_navigation_bar"
tools:context=".MainActivity"
android:descendantFocusability="blocksDescendants">

<RelativeLayout
android:id="@+id/productsLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="50dp"
android:orientation="vertical"
android:background="#EBE7E7"
>

<TextView
android:id="@+id/productsLayoutTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:lineSpacingExtra="0sp"
android:text="@string/produtos_em_destaque"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="normal"/>

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/productsLayoutTitle"
/>

<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:layout_alignBottom="@+id/recyclerView"
android:scaleX="1"
android:scaleY="1"
android:progressTint="#1C36FF"
/>

</RelativeLayout>
</RelativeLayout>

The code that is used to add data to the RecyclersView is

fun showData(products:Product,productsListSize:Int){

if(!isStarted){

  recyclerView.apply{
   layoutManager=LinearLayoutManager(this@MainActivity)
   adapter=ViewHolderAdapter(products,productsListSize)
   (adapter as ViewHolderAdapter).notifyItemRangeInserted(0,productsListSize)
   pageNumber++
  }

  progressBar.visibility=View.GONE
  isStarted=true
}else{

  recyclerView.apply{
    adapter=ViewHolderAdapter(products,pageNumber*limitPerPage)
    (adapter as ViewHolderAdapter).notifyItemRangeInserted(((pageNumber-1)*limitPerPage),pageNumber*limitPerPage)
    pageNumber++
  }
  progressBar.visibility=View.GONE
}

}

My ViewHolderAdapter


packagecom.example.kotlinbasics

importandroid.graphics.Color
importandroid.view.LayoutInflater
importandroid.view.View
importandroid.view.ViewGroup
importandroid.widget.ImageView
importandroid.widget.RatingBar
importandroid.widget.TextView
importandroidx.recyclerview.widget.RecyclerView
importcom.squareup.picasso.Picasso
importkotlinx.android.synthetic.main.recyclerview_layout.view.*

class ViewHolderAdapter(private val products:Product,private val productsListSize:Int):RecyclerView.Adapter<ViewHolderAdapter.ViewHolder>(){

override fun onCreateViewHolder(parent:ViewGroup,viewType:Int):ViewHolder{
val view=LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_layout,parent,false)
return ViewHolder(view)
}

override fun getItemCount()=productsListSize

override fun onBindViewHolder(holder:ViewHolder,position:Int){

holder.productName.text=products.produtos[position].nome
Picasso.get().load(products.produtos[position].img).into(holder.productImage)
}

class ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){

val productName:TextView=itemView.ProductName
val productImage:ImageView=itemView.ProductImage
}

}


All application works really fine, the only problem is with that scroll behavior. I expected that the scroll position didn't goes to the top of the RecyclersView list when I add new data in him.

Enzo Franzini
  • 59
  • 1
  • 6
  • This is caused by replacing adapter when data changes. You're only supposed to update the list it references and notify changes. – Pawel Jun 05 '19 at 18:13
  • You are creating a new adapter and set it to the RecyclerView every time, no wonder it will jump to the top. – HendraWD Jun 05 '19 at 19:08

3 Answers3

1

As you are creating a new adapter each time, the RecyclerView will be always going back to the start position. You have to update the current adapter, and not to create another adapter with the entire list.

You should have a method on your adapter to manage the item list, such as

fun updateList(product: Product) {
    myList.add(product.list)
}

And in your else branch you will need to update the list

recyclerView.apply{
    (adapter as? ViewHolderAdapter)?.updateList(products)
}
Diego Malone
  • 926
  • 8
  • 24
  • Hi Diego, first of all, thank you for helping me, you're the guy. I'm a beginner in Kotlin, so can you explain a little bit more detailed? I'll be very grateful. – Enzo Franzini Jun 05 '19 at 18:34
  • I am not able to provide more code because I don't have your `ViewHolderAdapter` code. But the main point is that you should keep the same adapter and only update the data. You may find [this answer](https://stackoverflow.com/questions/31367599/how-to-update-recyclerview-adapter-data?rq=1) helpful in how to achieve this. – Diego Malone Jun 05 '19 at 18:37
  • I edited and add the ViewHolderAdapter. He's pretty simple – Enzo Franzini Jun 05 '19 at 18:48
  • I think that my case is a little different of the link that you recommend me, because I do not use Lists inside my ViewHolderAdapter – Enzo Franzini Jun 05 '19 at 19:06
  • Yes, that is the problem. You will need a list in your `ViewHolderAdapter`. The adapter will receive additional elements to append to its list to allow the `RecyclerView` to maintain the current position. – Diego Malone Jun 05 '19 at 19:09
  • Valeu cara. Foi isso mesmo. Muito obrigado – Enzo Franzini Jun 06 '19 at 13:52
  • Nice! Also, be sure to use English in your comments. – Diego Malone Jun 06 '19 at 13:54
1

just use code bellow, and input requared position (in your case - last position) recyclerView.scrollToPosition()

1

Create one instance of your recycler view adapter , the pass the orignal list to it . whenever you want to add the any data , add it to the list , and then notify the adapter. In your case , Just add the product list and notify it

private list<product> list = newArrayList<>();

adapter= new ViewHolderAdapter(list);

OnClick of button when you want to add data , just insert it into the list

list.addAll(productlist);
And now notify it to the adapter 
adapter.notifyDataSetChange();

In your case

fun showData(products:Product,productsListSize:Int){

if(!isStarted){

         list.addAll(product)
          adapter.notifyDataSetChange();
          pageNumber++
    }

         progressBar.visibility=View.GONE
         isStarted=true
    }
    progressBar.visibility=View.GONE
 }

     }
Mini Chip
  • 771
  • 6
  • 9
  • I understand your point, but in my case, the list is already completed, I don't need to add nothing in the product's list. I just want to show the content in pages when the user scroll. – Enzo Franzini Jun 05 '19 at 19:46