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

Android RecyclerView滚动时未重新测量高度问题求助

问题

我的应用包含多个嵌套RecyclerView,其中一个横向RecyclerView的Item布局包含ImageView和作为新课程指示器的TextView。该指示器会在用户打开对应课程后设为View.GONE隐藏,仅在部分课程中显示(设为View.VISIBLE)。

当前该RecyclerView的layout_height设为wrap_content,当屏幕中仅显示无指示器的Item时,RecyclerView高度会适配ImageView;但横向滚动到带有指示器的Item时,RecyclerView无法重新计算高度,导致指示器视图被裁切。

我已尝试设置setHasFixedSize(false)等方法,但未解决问题。目前仅能通过固定RecyclerView高度解决,但希望获得更具扩展性的最优方案。请问如何让RecyclerView重新计算高度?

相关代码

RecyclerView布局代码

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv_video_packs"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/margin_16dp"
    android:clipToPadding="false"
    android:paddingEnd="16dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/rv_continue_watching" />

Item布局代码

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:focusable="true"
    android:clickable="true"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/iv_learn_item"
        android:visibility="invisible"
        android:layout_width="134dp"
        android:layout_height="200dp"
        android:adjustViewBounds="true"
        android:layout_marginStart="16dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:foreground="?attr/selectableItemBackground" />    

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/video_update_tv_guideline"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintGuide_begin="195dp"
        android:orientation="horizontal" />

    <TextView
        android:id="@+id/video_update_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="@id/iv_learn_item"
        app:layout_constraintEnd_toEndOf="@id/iv_learn_item"
        app:layout_constraintTop_toBottomOf="@+id/video_update_tv_guideline"
        android:layout_marginStart="@dimen/dimen_11dp"
        android:layout_marginEnd="@dimen/dimen_11dp"
        style="@style/content_update_pill" />

</androidx.constraintlayout.widget.ConstraintLayout>

Adapter初始化代码

rvVideoPacks.layoutManager =
    LinearLayoutManager(itemView.context, LinearLayoutManager.HORIZONTAL, false)
rvVideoPacks.setHasFixedSize(false)
rvVideoPacks.itemAnimator = null
rvVideoPacks.isNestedScrollingEnabled = true
rvVideoPacks.adapter = videoPackAdapter

补充:尝试将指示器设为invisible会导致底部留白,影响显示效果,希望RecyclerView能动态适配高度。

解决方案

方案1:自定义横向LinearLayoutManager重写测量逻辑

RecyclerView的wrap_content在横向布局下默认只会测量初始可见的Item高度,滚动后不会重新计算。可以自定义LinearLayoutManager,强制每次滚动后重新测量RecyclerView的高度:

class DynamicHeightLinearLayoutManager(context: Context) : LinearLayoutManager(context, HORIZONTAL, false) {

    override fun onLayoutCompleted(state: RecyclerView.State?) {
        super.onLayoutCompleted(state)
        val recyclerView = recyclerView ?: return
        recyclerView.post {
            recyclerView.requestLayout()
        }
    }

    override fun onScrollStateChanged(state: Int) {
        super.onScrollStateChanged(state)
        if (state == RecyclerView.SCROLL_STATE_IDLE) {
            val recyclerView = recyclerView ?: return
            recyclerView.post {
                recyclerView.requestLayout()
            }
        }
    }
}

替换原有的LayoutManager:

rvVideoPacks.layoutManager = DynamicHeightLinearLayoutManager(itemView.context)

方案2:在Adapter中更新指示器状态时主动触发重测量

当在Adapter的onBindViewHolder中设置指示器可见性时,主动通知RecyclerView重新计算高度:

override fun onBindViewHolder(holder: VideoPackViewHolder, position: Int) {
    val item = dataList[position]
    holder.videoUpdateTv.visibility = if (item.hasNewCourse) View.VISIBLE else View.GONE
    
    holder.itemView.post {
        rvVideoPacks.requestLayout()
    }
}

方案3:优化Item布局结构(推荐)

调整Item布局,让根容器始终占据包含指示器时的最大高度,避免RecyclerView高度频繁变化:

修改Item根布局,设置minHeight为ImageView高度加上指示器的高度与间距之和(比如假设指示器总占用高度为20dp,ImageView高度200dp,则设为220dp):

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:minHeight="220dp"
    android:focusable="true"
    android:clickable="true"
    android:orientation="vertical">

    <!-- 原有控件保持不变 -->

</androidx.constraintlayout.widget.ConstraintLayout>

这样RecyclerView初始就会以最大高度渲染,滚动时不会出现裁切,同时指示器设为GONE时也不会产生留白。


内容的提问来源于stack exchange,提问作者Saneen K P

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 16:50:21