简体   繁体   中英

Nested vertical recyclerviews scroll lag

My use case model looks like:

data class CombinedModel(
   val header: String?,
   val contactsList: List<ContactModel>
)

I have to display this model as List < CombinedModel > in a recyclerview so it will be a header title with a list of items below it. My Xml layout for the parent recyclerview is simply a MaterialTextView and a RecyclerView. The child recyclerview contains the layout for the list of ContactModel.

The problem is when scrolling down the parent list, each time a child RecyclerView comes onto screen there is a noticeable stutter/lag as it draws the next ContactModel list. The goal here would be to get this working with a smooth buttery scroll and no lag.

class ParentAdapter
constructor(
private val interaction: ContactAdapter.Interaction? = null,
private var customisedColour: String?
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(),
Filterable {

private val viewPool = RecyclerView.RecycledViewPool()

private var list = emptyList<DirectoryCombinedModel>()
private var listAll = directoryList
private val listFilter = ListFilter()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return ParentViewHolder(
        RvParentBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        ),
        interaction = interaction
    )
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    when (holder) {
        is ParentViewHolder -> {
            list[position].let { holder.bind(it) }
        }
    }
}

override fun getItemCount(): Int {
    return if (!list.isNullOrEmpty()) {
        list.size
    } else 0
}

fun updateList(updatedList: List<CombinedModel>) {
    list = updatedList
    listAll = updatedList
    notifyDataSetChanged()
}

inner classParentViewHolder
constructor(
    private val binding: RvParentBinding,
    private val interaction: ContactAdapter.Interaction?
) : RecyclerView.ViewHolder(binding.root) {

    fun bind(item: CombinedModel) = with(itemView) {
        with(binding) {

            headerTitle.text = item.header

            val childLayoutManager = GridLayoutManager(
                rv.context, 2
            )
            childLayoutManager.initialPrefetchItemCount = item.contactList.size

            rv.apply {
                layoutManager = childLayoutManager
                adapter = ContactAdapter(
                    interaction = interaction,
                    customisedColour = customisedColour,
                    contacts = item.contactsList
                )
                setHasFixedSize(true)
                setRecycledViewPool(viewPool)
            }
        }
    }
}

PARENT XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout   xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<com.google.android.material.card.MaterialCardView
    android:id="@+id/cvHeader"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardBackgroundColor="@color/transparent"
    app:cardCornerRadius="0dp"
    app:cardElevation="0dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/headerTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="start"
        android:paddingStart="@dimen/_8sdp"
        android:paddingTop="@dimen/_18sdp"
        android:paddingEnd="@dimen/_8sdp"
        android:paddingBottom="@dimen/_12sdp"
        android:text="@string/title"
        android:textColor="@color/textColorPrimary"
        android:textSize="@dimen/text_size_subHeading"
        android:textStyle="bold" />
</com.google.android.material.card.MaterialCardView>

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:nestedScrollingEnabled="false"
    app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/cvHeader"
    app:spanCount="2"
    tools:listitem="@layout/rv_contact" />

</androidx.constraintlayout.widget.ConstraintLayout>

CHILD ADAPTER

class DirectoryContactAdapter
constructor(
private val interaction: Interaction? = null,
private val customisedColour: String?,
private var contacts: List<ContactModel>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

private var contactsAll = contacts

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {

    return ContactViewHolder(
        RvContactBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        ),
        interaction = interaction
    )
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    when (holder) {
        is ContactViewHolder -> {
            contacts[position].let { holder.bind(it) }
        }
    }
}

override fun getItemCount(): Int {
    return if (!contacts.isNullOrEmpty()) {
        contacts.size
    } else 0
}

inner class ContactViewHolder
constructor(
    private val binding: RvContactBinding,
    private val interaction: Interaction?
) : RecyclerView.ViewHolder(binding.root) {

    fun bind(item: ContactModel) = with(itemView) {
        with(binding) {

            setOnClickListener {
                interaction?.onItemSelected(absoluteAdapterPosition, item)
            }

            name.text = item.name
            role.text = item.title

            Glide.with(contactImage.context)
                .load(item.imageName)
                .centerCrop()
                .circleCrop()
                .placeholder(R.drawable.ic_contact)
                .error(R.drawable.ic_contact)
                .transition(
                    DrawableTransitionOptions.withCrossFade()
                ).into(contactImage)

            directoryImageBackground.setTintHex(customisedColour)

        }
    }
}

Solved it by following the approach layed out in this accepted answer: Divide elements on groups in RecyclerView or Grouping Recyclerview items,say by date

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM