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

vbkedwbf  于 2022-09-21  发布在  Android
关注(0)|答案(9)|浏览(144)

我需要确保水平回收器查看高度与最大项目的高度相同。

项目可以有不同的高度(项目=始终相同的图像+标题+字幕,标题和字幕可以有无限的长度)。当我为回收者视图设置WRAP_CONTENT时,它会根据可见项目的高度调整大小,这会使回收者视图下方的内容跳跃,这是我想要避免的。

我想要实现的是:灰色区域是可见的视区。

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

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

jgovgodb

jgovgodb1#

我刚刚也遇到了这个问题。我的解决方案是:

1.将循环视图 Package 在ConstraintLayout中。
1.设置ConstraintLayout的Layout_Height为WRAP_CONTENT。
1.将项目视图添加到ConstraintLayout,并使用您根据其标题长度预期最高的项目的数据填充它。
1.将条目视图的可见性设置为不可见。
1.将循环视图的Layout_Height设置为零,并使其顶部和底部约束与项目视图的顶部和底部约束匹配。

oogrdqng

oogrdqng2#

现在还来不及回答,但也许这会对某人有所帮助。

我为同样的问题而苦苦挣扎,也找不到一个可以接受的解决方案。

解决方法如下:

1)首先,您需要从循环视图重写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中,将RecycleView替换为此CustomRecycleView:

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

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

3)要在开始时做到这一点,您必须破解(基于@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毫秒后设置为可见,以使此过程对用户不可见。此外,滚动到Start的执行延迟为300毫秒,因为如果没有一些延迟,它可能无法正常工作。在我的例子中,这是包含3个元素的列表所需要的,而这些延迟对我来说是最好的。

还要记住删除onStop()中的所有处理程序回调

vc9ivgsu

vc9ivgsu3#

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

让我们花一点时间来思考一下RecclerView是如何工作的。为了节省内存,它重用了相同的View对象,并在用户滚动时将它们绑定到列表中的新数据。因此,例如,如果用户看到项目0和1,则系统只测量和布局了2个项目(可能还有一两个项目来帮助提高滚动性能)。

但假设您的最高项是列表中的第50位,当RecclerView绑定前几个项时,它根本不知道第50项的存在,更不用说它会有多高。

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

这不是最优雅的解决方案,但它应该会奏效。

k7fdbhmy

k7fdbhmy4#

创建了一种通过尝试列表中的所有描述以获得最高高度来计算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;
        }
    }

然后在onBindViewHolder中使用这个highestHeight`来设置Description的高度,使所有的视图始终具有与最高高度相同的高度。

viewHolder.description.setHeight(highestHeight);

代码在https://github.com/dk19121991/HorizontalRecyclerWithDynamicHeight中提交

如果这解决了你的问题,让我知道,如果你有更多的问题,请随时提问。

谢谢

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

wnvonmuf

wnvonmuf5#

你可以试试这个:

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

xmd2e60i6#

您应该尝试不同的Item_VIEW类型

b1payxdu

b1payxdu7#

尝尝这个

@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设置为固定高度。

nkhmeac6

nkhmeac68#

我做了1c0c1d,解决了问题。
recyclerView.getRecycledViewPool().setMaxRecycledViews(TYPE_CAROUSEL, 0);

如果有很多项目,这个解决方案可能会有性能问题,但对于几个项目,比如说5到20个项目,就可以很好地工作,我就是这样做的。

xdnvmnnf

xdnvmnnf9#

RecyclerViewHorizontal.setMinimumHeight(maxItemHeight)对我来说运行得很好。

相关问题