RecyclerView中的item宽度layout_width="match_parent"与父容器不匹配。

10

我正在使用RecyclerView,并尝试使RecyclerView的宽度匹配_parent,因为我正在使用

LinearLayoutManager.HORIZONTAL

运行后的RecyclerView项目

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

布局管理器

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

视图持有者

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

@Rami感谢您的评论,我已尝试了两种建议的解决方案,但问题仍然存在。而且我不认为问题出在CardView上,因为我将其更改为“FrameLayout”,但问题仍然存在。 - Diyaa
我找到的最佳解决方案在这里: https://dev59.com/P1sV5IYBdhLWcg3wsQrf#62139337 - Noman Srl
4个回答

18

我解决了这个问题:

1- 获取屏幕尺寸(宽度)。

2- 将 ViewHolder 的宽度设置为屏幕尺寸。

以下是我的代码,如果有人需要的话。

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

在 Kotlin 中,您可以在适配器的 onCreateViewHolder 函数中,在 return 之前使用以下代码: val outMetrics = DisplayMetrics() val display = parent.display display?.getRealMetrics(outMetrics) itemView.layoutParams = RecyclerView.LayoutParams(outMetrics.widthPixels, RecyclerView.LayoutParams.MATCH_PARENT) - mafortis

8

注意:请查看本文末尾的更新内容。


旧版回答:

以下方法适用于我:

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

在填充视图“view”后,紧接着进行以下操作。

它基本上采用父级的宽度,并将新视图的layout_width替换为父级的宽度。

您还可以添加一个匹配父级的检查,以确保在未来将XML修改为不同宽度时正确显示。就像这样:

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

如果宽度在此之前是MATCH_PARENT,则此操作将使其等于父宽度。

编辑:

请注意不要过度使用此修复程序,因为其中的一种变体已经导致了布局错误。我曾这样做:

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

那个方法起作用了,但当RecyclerView调整大小时,它没有更新宽度和高度。因此,可以应用以下两种修复方法之一:
  1. 检查RecyclerView适配器的方向,并仅在滚动允许的维度上使用parent.getHeight()等来进行此操作。
  2. 或者,在ViewHolder某个位置保存原始的“宽度”和“高度”,然后在onBindViewHolder()方法中每次重新执行此步骤。
以下修正似乎有效:
    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. 
    } 

注意: 如果您在onBindViewHolder()方法中使用此调整大小的方法,您还需要在Activity.onSizeChanged()内使用getAdapter().notifyDataSetChanged()

简而言之,主要思路是:每次bind时都检查MATCH_PARENT,而不仅仅是创建视图持有者时。这样调整RecyclerView大小也可以正常工作。


更新:自RecyclerView v7.23.2.1版本以来,似乎已经修复了这个问题,现在不再需要这些自定义修复程序了。RecyclerView本身现在应该能够识别WRAP_CONTENT和MATCH_PARENT设置。


这个对我很有效。然而,我使用的是view.setLayoutParams(new LinearLayout.LayoutParams(viewGroup.getWidth(), ViewGroup.LayoutParams.WRAP_CONTENT));而不是view.getLayoutParams().width = ...。原因是view.getLayoutParams可能为空(在我的情况下确实如此,原因很奇怪)。 - Igor
@Igor 谢谢。我在上面的编辑中已经考虑到了这一点。 - RhetoricalRuvim

4

从布局中删除此内容。

android:layout_weight="1"

再次为适配器中的项目设置布局参数。

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;

1
我做了,但没有任何变化。 - Diyaa

1

使用GridLayoutManager而不是LinearLayoutManager,并将列数设置为1是最简单的方法。

从您的xml文件中:

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

或者来自 Kotlin:

recyclerView.layoutManager = GridLayoutManager(this,1)

或者从Java:

recyclerView.setLayoutManager(new GridLayoutManager (this, 1);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接