You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让NestedScrollView内的RecyclerView保持正常视图复用特性?

解决RecyclerView在NestedScrollView中失去项复用的问题

你的问题核心在于RecyclerView的layout_height设为wrap_content时,放在NestedScrollView中会强制测量所有子项的总高度,导致一次性创建所有ViewHolder,完全失去复用特性,进而出现加载等待的卡顿。下面提供两种解决方案:

方案一:保留NestedScrollView,修复RecyclerView的高度约束

只需要修改布局中RecyclerView的属性,让它填充父布局的可用空间,而非自适应内容高度:

修改fragment_translate_from.xml中的RecyclerView部分:

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/all_langs_recycler_view"
    android:layout_width="0dp"
    android:layout_height="0dp" <!-- 从wrap_content改为0dp -->
    android:nestedScrollingEnabled="false"
    android:orientation="vertical"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/tv_all_languages"
    app:layout_constraintBottom_toBottomOf="parent" /> <!-- 添加底部约束 -->

原理

当RecyclerView高度设为0dp并通过约束填充可用空间时,它会基于当前可见区域的高度来创建ViewHolder,而非一次性加载所有项,这样就保留了复用特性,解决卡顿问题。

方案二:移除NestedScrollView,使用RecyclerView Header替代单独标题(更优)

如果你的布局中只有标题+RecyclerView需要滚动,完全不需要NestedScrollView,直接把标题作为RecyclerView的Header,性能更优:

步骤1:创建Header Adapter

class LanguageHeaderAdapter(private val title: String) : RecyclerView.Adapter<LanguageHeaderAdapter.HeaderViewHolder>() {
    class HeaderViewHolder(private val binding: LanguageHeaderBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(title: String) {
            binding.tvTitle.text = title
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder {
        val binding = LanguageHeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return HeaderViewHolder(binding)
    }

    override fun onBindViewHolder(holder: HeaderViewHolder, position: Int) {
        holder.bind(title)
    }

    override fun getItemCount(): Int = 1
}

步骤2:修改Fragment中的Adapter初始化

在setAllLanguagesRecyclerView方法中,用ConcatAdapter合并Header和语言列表Adapter:

private fun setAllLanguagesRecyclerView() {
    lifecycleScope.launch(Dispatchers.IO) {
        languagesList = viewModel.getAllLanguagesName().toMutableList()
        val layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
        val position = viewModel.getAllSelectedPosition()

        val adapter = AllLanguagesAdapter { allLangModel ->
            viewModel.insertRecentLanguages(allLangModel)
            sendBackValueToPreviousBackStack(allLangModel.langCode)
        }
        // 添加Header
        val headerAdapter = LanguageHeaderAdapter(getString(R.string.all_languages_str))
        val concatAdapter = ConcatAdapter(headerAdapter, adapter)

        binding.allLangsRecyclerView.layoutManager = layoutManager
        adapter.submitList(languagesList)
        withContext(Dispatchers.Main) {
            binding.allLangsRecyclerView.adapter = concatAdapter // 使用合并后的Adapter
            setBackgroundToLanguagesRecyclerViewItem(
                recyclerView = binding.allLangsRecyclerView,
                position = position + 1 // 注意Header占了一个位置,position需要+1
            )
            setAdiveryNativeAd(adapter)
            setSearch(adapter)
        }
    }
}

步骤3:简化布局

移除NestedScrollView和内层ConstraintLayout,直接让RecyclerView填充父布局:

<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/views_layout_translate_from"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/all_langs_recycler_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="vertical"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

原理

RecyclerView本身就具备完整的滚动和复用机制,添加Header后依然会正常复用列表项,同时避免了NestedScrollView带来的额外测量开销,是性能最优的方案。

内容的提问来源于stack exchange,提问作者StackOverflower

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 05:47:02