14

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

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

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

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

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

4

8 回答 8

8

我也有这个问题。我的解决方案是:

  1. 将 RecyclerView 包装在 ConstraintLayout 中。
  2. 将 ConstraintLayout 的 layout_height 设置为 wrap_content。
  3. 将项目视图添加到 ConstraintLayout 并使用您希望根据其标题的长度达到最高的项目的数据填充它。
  4. 将项目视图的可见性设置为不可见。
  5. 将 RecyclerView 的 layout_height 设置为零,并使其顶部和底部约束与项目视图的约束匹配。
于 2020-04-08T10:08:47.453 回答
4

我不认为这是开箱即用的。

让我们想一想 RecyclerView 是如何工作的。为了节省内存,它重用相同的 View 对象,并在用户滚动时将它们绑定到列表中的新数据。因此,例如,如果用户看到项目的 0 和 1,那么系统只测量并布置了 2 个项目(可能还有一两个以帮助滚动性能)。

但是假设你的高项目是列表中的第 50 号,当 RecyclerView 绑定前几个项目时,它根本不知道第 50 项是否存在,更不用说它有多高了。

但是,你可以做一些有点 hacky 的事情。例如,您可以在绑定后测量每个项目的高度,跟踪最高的,然后手动将 RecyclerView 高度设置为该大小。使用该机制,您可以隐藏 RecyclerView,然后手动滚动到列表的末尾,滚动回列表的开头,然后显示 RecyclerView。

不是最优雅的解决方案,但它应该可以工作。

于 2019-09-11T13:36:26.450 回答
3

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

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

通过以下方式解决:

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))
    }

}

2)在你的layput中用这个CustomRecycleView替换RecycleView:

<CustomRecycleView
   android:layout_width="match_parent"
   android:layout_height="wrap_content" />

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

3)要在开始时执行此操作,您必须进行 hack(基于@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)
}

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

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

于 2019-12-13T09:45:09.367 回答
1

你可以试试这个:

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            final int newHeight = recyclerView.getMeasuredHeight();
            if (0 != newHeight && minHeight < newHeight) {
            // keep track the height and prevent recycler view optimizing by resizing
                minHeight = newHeight;
                recyclerView.setMinimumHeight(minHeight);
            }
        }
    });
于 2019-12-05T07:50:09.813 回答
1

创建了一种方法来计算 textView 的投影高度,方法是尝试列表中的所有描述以获得最高高度。

 public static int getHeightOfLargestDescription(final Context context, final CharSequence text, TextView textView) {
    final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    final Point displaySize = new Point();
    wm.getDefaultDisplay().getSize(displaySize);
    final int deviceWidth = displaySize.x;
    textView.setTypeface(Typeface.DEFAULT);
    textView.setText(text, TextView.BufferType.SPANNABLE);
    int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(deviceWidth, View.MeasureSpec.AT_MOST);
    int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    textView.measure(widthMeasureSpec, heightMeasureSpec);
    return textView.getMeasuredHeight();
}

然后使用此方法来onCreateViewHolder准备在绑定视图时使用的最高高度。

        MyViewHolder myViewHolder = new MyViewHolder(itemView);
    for (Model m : modelList) {
        currentItemHeight = getHeightOfLargestDescription(context, m.description, myViewHolder.description);
        if (currentItemHeight > highestHeight) {
            highestHeight = currentItemHeight;
        }
    }

然后highestHeight在 onBindViewHolder 中使用这个来设置描述 TexView 的高度,这样所有的视图总是有相同的高度,等于最高的高度。

 viewHolder.description.setHeight(highestHeight);

代码提交在 https://github.com/dk19121991/Horizo​​ntalRecyclerWithDynamicHeight

在此处输入图像描述

让我知道这是否解决了您的问题,如果您还有更多问题,请随时提出。

谢谢

要查看有关此解决方案的完整讨论,请参阅下面的 https://stackoverflow.com/a/67403898/4828650

于 2021-05-05T15:07:25.580 回答
0

你应该尝试不同的 item_view 类型

于 2019-09-11T13:23:31.223 回答
0

尝试这个

    @Override
     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

     View itemView = mLayoutInflater.inflate(R.layout.view_item, parent, false);
    // work here if you need to control height of your items
    // keep in mind that parent is RecyclerView in this case
    int height = parent.getMeasuredHeight() / 4;
    itemView.setMinimumHeight(height);
    return new ItemViewHolder(itemView);        
    }

或者你也可以试试这个

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View itemView = inflater.inflate(R.layout.itemview, parent, false);

    ViewGroup.LayoutParams layoutParams = itemView.getLayoutParams();
    layoutParams.height = (int) (parent.getHeight() * 0.3);
    itemView.setLayoutParams(layoutParams);

    return new MyViewHolder(itemView);
   }

您还可以将 itemView 设置为固定高度。

于 2019-09-11T13:29:42.137 回答
0

在回收站视图中禁用了回收,它解决了这个问题。

recyclerView.getRecycledViewPool().setMaxRecycledViews(TYPE_CAROUSEL, 0);

如果有很多项目,这个解决方案可能会出现性能问题,但对于一些项目来说可以正常工作,比如说 5 到 20,这对我来说就是这种情况。

于 2021-03-25T15:54:06.317 回答