Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set recycler height to highest item in recyclerView?

I need to make sure that horizontal recyclerView height is the same as the height of the biggest item.

Items can have a different height (Item = always the same image + title + subtitle, title and subtitle could have infinite length). When I set wrap_content for my recyclerView it would resize, basing on the height of visible items which makes content below recyclerView jump, and that's something I want to avoid.

What I want to achieve: what I want to achive The gray area is visible viewport.

So basically I would like to get somehow hight of the biggest item, then put recyclerView height to that number.

What I already tried is approximation high of items based on length of title + subtitle but it's very inaccurate because for example even if two titles have the same text length they could have different width because of font that I use which is not a monospace font.

like image 563
Jakub Mosakowski Avatar asked Sep 11 '19 13:09

Jakub Mosakowski


People also ask

How do you change the maximum height of a recycler view?

DisplayMetrics displaymetrics = new DisplayMetrics(); getWindowManager(). getDefaultDisplay(). getMetrics(displaymetrics); int a = (displaymetrics. heightPixels * 60) / 100; recyclerview1.

How do you set different height for each item in recycler view?

solution: In the item layout xml, use RelativeLayout as root only and ensure the layout whose child view be dynamically added is surrounded with RelativeLayout too. Save this answer.

How do I reduce space between items in RecyclerView?

Try to use cardElevation=0dp. This should remove the extra spacing between recyclerview items.

What is layout manager in RecyclerView?

A LayoutManager is responsible for measuring and positioning item views within a RecyclerView as well as determining the policy for when to recycle item views that are no longer visible to the user.


2 Answers

Too late for an answer, but maybe this will help someone.

I struggled with the same issue and couldn't find an acceptable solution.

Solved by following:

1) First, you need to override onMeasure from the RecyclerView to save the largest element height:

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) In you layput replace RecycleView with this CustomRecycleView:

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

onMeasure is called when a new element in the list is visible, and if the element is the highest, then we save this value. For example: if the first element has lowest height but lates has highest then at start RecycleView will be have height match to first element but after scrolling it will stay match to highest. If you don't need to make RecycleView height match to highest item at start then you can stop here.

3) To do this at the beginning, you must make a hack (based on @MidasLefko suggestion): To find out initially what the height of the highest element will be, you need to add a scroll mechanism to the end and the beginning. I did it as follows:

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

Set the visibility of Recycle view to INVISIBLE and after 700 milliseconds to VISIBLE to make this process invisible for user. Also, scrolling to start is performed with a delay of 300 milliseconds, because without some delay it can work incorrectly. In my case, this is needed for a list of 3 elements, and these delays is optimal for me.

Also remember to remove all Handler callbacks in onStop ()

like image 187
Anonymous Avatar answered Sep 20 '22 23:09

Anonymous


Created a method to calculate the projected height of textView by trying all the description in the list to get the highest height.

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

then used this method to in onCreateViewHolder to get ready with the highest height to be used while binding the view.

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

Then used this highestHeight in onBindViewHolder` to set the height of the description TexView, so that all the views always have the same height that is equal to the highest height.

 viewHolder.description.setHeight(highestHeight);

Code is committed in the https://github.com/dk19121991/HorizontalRecyclerWithDynamicHeight

enter image description here

Let me know if this solves your problem, if you have some more question feel free to ask.

Thanks

To view a full discussion on this solution please see below https://stackoverflow.com/a/67403898/4828650

like image 33
Dinkar Kumar Avatar answered Sep 21 '22 23:09

Dinkar Kumar