如何将回收器高度设置为 recyclerView 中的最高项目?

Jak*_*ski 12 android android-recyclerview android-wrap-content

我需要确保水平 recyclerView 高度与最大项目的高度相同。

项目可以有不同的高度(项目 = 总是相同的图像 + 标题 + 副标题,标题和副标题可以有无限长度)。当我为我的 recyclerView 设置 wrap_content 时,它会根据可见项目的高度调整大小,这使得 recyclerView 下方的内容跳跃,这是我想要避免的。

我想要达到的目标: 我想要达到的目标 灰色区域是可见视口。

所以基本上我想以某种方式获得最大项目的高度,然后将 recyclerView 高度设置为该数字。

我已经尝试过的是基于标题 + 副标题长度的近似值,但它非常不准确,因为例如,即使两个标题具有相同的文本长度,它们也可能具有不同的宽度,因为我使用的字体不是等宽字体。

Ely*_*our 8

我也刚遇到这个问题。我的解决办法是:

  1. 将 RecyclerView 包裹在 ConstraintLayout 中。
  2. 将 ConstraintLayout 的 layout_height 设置为 wrap_content。
  3. 将一个项目视图添加到 ConstraintLayout 并使用您期望的最高项目的数据填充它,例如根据其标题的长度。
  4. 将项目视图的可见性设置为不可见。
  5. 将 RecyclerView 的 layout_height 设置为零,并使其顶部和底部约束与项目视图的约束相匹配。


Ano*_*ous 6

答案为时已晚,但这也许会对某人有所帮助。

我在同样的问题上苦苦挣扎,但找不到可接受的解决方案。

通过以下方法解决:

  1. 首先,您需要从 RecyclerView 重写 onMeasure 以保存最大元素高度:
class CustomRecycleView(ctx: Context, attrs: AttributeSet) : RecyclerView(ctx, attrs) {

    private var biggestHeight: Int = 0

    override fun onMeasure(widthSpec: Int, heightSpec: Int) {
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            child.measure(widthSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
            val h = child.measuredHeight
            if (h > biggestHeight) biggestHeight = h
        }

        super.onMeasure(widthSpec, MeasureSpec.makeMeasureSpec(biggestHeight, MeasureSpec.EXACTLY))
    }
  
}
Run Code Online (Sandbox Code Playgroud)
  1. 在您的布局中,将 RecycleView 替换为 CustomRecycleView:

onMeasure 当列表中的新元素可见时调用,如果该元素是最高的,那么我们保存该值。例如:如果第一个元素具有最低高度,但最新元素具有最高高度,那么在开始时 RecycleView 的高度将与第一个元素匹配,但滚动后它将保持与最高高度匹配。如果您不需要在开始时使 RecycleView 高度与最高项目匹配,那么您可以到此为止。

  1. 要在开始时执行此操作,您必须进行黑客攻击(基于@MidasLefko建议):为了最初找出最高元素的高度,您需要在末尾和开头添加滚动机制。我是这样做的:
private fun initRecycleView(items: ArrayList<Object>) {
    val adapter = Adapter()
    rv.visibility = View.INVISIBLE
    rv.vadapter = adapter
    rv.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
    rv.setHasFixedSize(true)
    rv.smoothScrollToPosition(pinnedPosts.size)
    Handler().postDelayed({
        rv.smoothScrollToPosition(0)
    }, 300)
    Handler().postDelayed({
        rv.visibility = View.VISIBLE
    }, 700)
}
Run Code Online (Sandbox Code Playgroud)

将“回收”视图的可见性设置为“不可见”,并在 700 毫秒后设置为“可见”,以使此进程对用户不可见。此外,滚动启动会延迟 300 毫秒,因为如果没有延迟,它可能会无法正常工作。就我而言,这对于包含 3 个元素的列表是必需的,并且这些延迟对我来说是最佳的。

还记得去掉onStop()中所有的Handler回调


小智 0

你应该尝试使用不同的 item_view 类型