嵌套的垂直回收视图滚动滞后

Nested vertical recyclerviews scroll lag

我的用例模型如下:

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

我必须在 recyclerview 中将此模型显示为 List < CombinedModel >,这样它将是一个 header 标题,下面有一个项目列表。我的 Xml parent recyclerview 布局只是一个 MaterialTextView 和一个 RecyclerView。 child recyclerview 包含 ContactModel 列表的布局。

问题是向下滚动 parent 列表时,每次 child RecyclerView 出现在屏幕上时,都会有一个明显的 stutter/lag,因为它会绘制下一个 ContactModel 列表。这里的目标是让它在平滑的黄油滚动和无延迟的情况下工作。

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 适配器

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)

        }
    }
}

按照这个接受的答案中列出的方法解决了这个问题: