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

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

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.