RecyclerView item width layout_width=“match_parent” does not match parent

22,324

Solution 1

I fixed the problem:

1- Get the screen size (width).

2- make the ViewHolder width same as screen size.

Below my code if any one need it.

WindowManager windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        int width = windowManager.getDefaultDisplay().getWidth();
        int height = windowManager.getDefaultDisplay().getHeight();
        view.setLayoutParams(new RecyclerView.LayoutParams(width, RecyclerView.LayoutParams.MATCH_PARENT));

Solution 2

Note: See update at the very end of this post.


Old Answer:

The following worked for me:

view.getLayoutParams ().width = parentViewGroup.getWidth (); 

, right after inflating the view 'view' .

It basically takes the width of the parent and replaces the new view's layout_width with the parent's width.

You can also add a check for MATCH_PARENT, to make sure it appears correctly in case you modify the XML to a different width in the future. So like this:

    public ViewHolder onCreateViewHolder (ViewGroup parent, int type) {
        View vItem = LayoutInflater.from (parent.getContext ()) 
                             .inflate (R.layout.bookmark_card, parent, false); 
        if (vItem.getLayoutParams ().width == RecyclerView.LayoutParams.MATCH_PARENT) 
            vItem.getLayoutParams ().width = parent.getWidth (); 
        return new ViewHolder (vItem); 
    } 

It will only make it the parent width if the width was MATCH_PARENT before this.

EDIT:

Do be careful about excessive use of this fix, as a variation of it has caused me a layout bug. I did this:

    public ViewHolder onCreateViewHolder (ViewGroup parent, int type) { 
        View vItem = LayoutInflater.from (parent.getContext ()) 
                             .inflate (R.layout.page_tile, parent, false); 
        if (vItem.getLayoutParams ().width == RecyclerView.LayoutParams.MATCH_PARENT) 
            vItem.getLayoutParams ().width = parent.getWidth (); 
        if (vItem.getLayoutParams ().height == RecyclerView.LayoutParams.MATCH_PARENT) 
            vItem.getLayoutParams ().height = parent.getHeight (); 
        return new ViewHolder (vItem); 
    } 

That worked, but it did not update the width and height when the RecyclerView was resized. Therefore, one of two fixes to this fix can be applied:

  1. Check for RecyclerView adapter orientation, and only do this parent.getHeight (), etc., for the dimensions along which scrolling is allowed.
  2. Or, somewhere in the ViewHolder, save the original 'width' and 'height', and then redo this step every time in the onBindViewHolder () method.

The following fix seems to work:

    public ViewHolder onCreateViewHolder (ViewGroup parent, int type) { 
        View vItem = LayoutInflater.from (parent.getContext ()) 
                             .inflate (R.layout.page_tile, parent, false); 
        ViewHolder holder = new ViewHolder (vItem); // Create view holder. 
        holder.vItem = vItem; // Save top-level View. 
        holder.vParent = parent; // Save its parent. 
        ViewGroup.LayoutParams lp = vItem.getLayoutParams (); 
        if (lp != null) { // Save the original width and height from lp: 
            holder.originalWidth = lp.width; 
            holder.originalHeight = lp.height; 
            refreshLayoutParams (holder); // Check for MATCH_PARENT. 
        } else holder.originalHeight = holder.originalWidth = 0; 
        return holder; 
    } 
    public void onBindViewHolder (ViewHolder holder, int position) { 
        ... do work here ... 
        refreshLayoutParams (holder); // Check AGAIN for MATCH_PARENT. 
    } 
    private void refreshLayoutParams (ViewHolder holder) {
        ViewGroup.LayoutParams lp = holder.vItem.getLayoutParams (); 
        View parent = holder.vParent; 
        if (parent == null) return; // Is there a parent to check against? 
        if (lp == null) 
            holder.vItem.setLayoutParams (lp = 
                            new RecyclerView.LayoutParams (holder.originalWidth, holder.originalHeight)); 
        if (holder.originalWidth == RecyclerView.LayoutParams.MATCH_PARENT) 
            lp.width = parent.getWidth (); // Check width. 
        if (holder.originalHeight == RecyclerView.LayoutParams.MATCH_PARENT) 
            lp.height = parent.getHeight (); // Check height. 
    } 

Note Also: If you use this approach of resizing inside the onBindViewHolder () method, you will also need to getAdapter ().notifyDataSetChanged () inside the Activity.onSizeChanged ()!

In short, the main idea is: check for MATCH_PARENT on every bind, not just on create view holder. This way resizing the RecyclerView works too.


UPDATE: As of RecyclerView v7:23.2.1 at least, it seems they have fixed it so that now these custom fixes are no longer necessary. RecyclerView itself should now recognize both WRAP_CONTENT and MATCH_PARENT settings.

Solution 3

Remove this in the layout.

android:layout_weight="1"

And set layout params for item in adapter once again.

View view= LayoutInflater.from(parent.getContext())
                .inflate(R.layout.custom_layout, parent, false);
view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.MATCH_PARENT));
ViewOffersHolder viewHolder=new ViewOffersHolder(view);
return viewHolder;

Solution 4

Calling to GridLayoutManager instead of LinearLayoutManager and put one column is most simple

From your xml:

<androidx.recyclerview.widget.RecyclerView
        app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
        app:spanCount="1"
...

Or from Kotlin:

recyclerView.layoutManager = GridLayoutManager(this,1)

Or from Java:

recyclerView.setLayoutManager(new GridLayoutManager (this, 1);
Share:
22,324
Diyaa
Author by

Diyaa

Technology Head at Floward; Software Engineer | C# | JavaScript | Python Requeue and Foodiyoo app Co-Founder

Updated on August 23, 2020

Comments

  • Diyaa
    Diyaa almost 4 years

    I'm using RecyclerView and I'm trying to make the width item of RecyclerView match_parent since I'm using

    LinearLayoutManager.HORIZONTAL

    RecyclerView items after running

     <android.support.v7.widget.RecyclerView
                android:id="@+id/listOffersHits"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
    

    custom_layout.xml

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:layout_margin="2dp"
        card_view:cardCornerRadius="2dp">
        <ImageView
            android:id="@+id/offerImage"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
    
            android:background="@drawable/item_selector"
            android:scaleType="fitXY"
            android:src="@drawable/offer"
            />
    
    </android.support.v7.widget.CardView>
    

    LayoutManager

       LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity(),LinearLayoutManager.HORIZONTAL, false);
        listOffersHits.setLayoutManager(linearLayoutManager);
    

    ViewHolder

    View view= LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.custom_layout, parent, false);
            ViewOffersHolder viewHolder=new ViewOffersHolder(view);
            return viewHolder;
    
  • Diyaa
    Diyaa almost 9 years
    I did it but no change.
  • Igor
    Igor over 8 years
    This one worked nicely for me. However: instead of using view.getLayoutParams().width = ..., I did view.setLayoutParams(new LinearLayout.LayoutParams(viewGroup.getWidth(), ViewGroup.LayoutParams.WRAP_CONTENT)); instead. The reason is that view.getLayoutParams might be null (which it was in my case for some weird reason).
  • RhetoricalRuvim
    RhetoricalRuvim about 8 years
    @Igor Thank you. I took this into account when making my edit above.
  • mafortis
    mafortis over 3 years
    or in kotlin you can use val outMetrics = DisplayMetrics() val display = parent.display display?.getRealMetrics(outMetrics) itemView.layoutParams = RecyclerView.LayoutParams(outMetrics.widthPixels, RecyclerView.LayoutParams.MATCH_PARENT) inside your adapter onCreateViewHolder function right before return