CardView layout_width="match_parent" не соответствует ширине родительского RecyclerView

У меня есть фрагмент с содержит RecyclerView с layout_width="match_parent":

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity$PlaceholderFragment" />

Элемент в RecyclerView - это CardView также с layout_width="match_parent":

<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_gravity="center"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="20dp"
    card_view:cardCornerRadius="4dp">

    <TextView
        android:layout_gravity="center"
        android:id="@+id/info_text"
        android:layout_width="match_parent"
        android:gravity="center"
        android:layout_height="match_parent"
        android:textAppearance="?android:textAppearanceLarge"/>
</android.support.v7.widget.CardView>

Я раздуваю вид элемента, как показано ниже:

public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                   int viewType) {
        CardView v = (CardView) LayoutInflater.from(parent.getContext())
                .inflate(R.layout.card_listitem, null, true);

        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

Но когда я запускаю приложение, CardView отображается как wrap_content, как показано ниже:

CardsBug

Обратите внимание, что это было запущено на эмуляторе, а не на реальном устройстве.

Я что-то не так делаю или это ошибка?

10 ответов

Решение

Документы для inflate:

Раздуть новую иерархию представлений из указанного ресурса xml. Выдает InflateException, если есть ошибка.

параметры
ID ресурса для ресурса макета XML для загрузки (например, R.layout.main_page) root
представление, чтобы быть родителем сгенерированной иерархии (если attachToRoot - true), или просто объект, который предоставляет набор значений LayoutParams для корня возвращаемой иерархии (если attachToRoot - false.)
attachToRoot Должна ли завышенная иерархия быть присоединена к корневому параметру? Если false, root используется только для создания правильного подкласса LayoutParams для корневого представления в XML. Возвращает корневой вид завышенной иерархии. Если указан root и attachToRoot имеет значение true, это root; в противном случае это корень завышенного XML-файла.

Здесь важно не указывать истину, а указывать родителя:

LayoutInflater.from(parent.getContext())
            .inflate(R.layout.card_listitem, parent, false);

Поставка parent Вид позволяет инфлятору знать, какие макеты использовать. Поставка false Параметр говорит, что пока не следует прикреплять его к родителю. Это то, что RecyclerView сделаю для тебя.

Используйте RelativeLayout в качестве непосредственного родителя для CardView.

<RelativeLayout 
    android:layout_width="match_parent" ... >
    <CardView 
        android:layout_width="match_parent" ... >
    </CardView>
</RelativeLayout>

Это сработало для меня,

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

Я сделал это так:

View view = mInflater.inflate(R.layout.row_cardview, null, true);
            WindowManager windowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
            int width = windowManager.getDefaultDisplay().getWidth();
            view.setLayoutParams(new RecyclerView.LayoutParams(width, RecyclerView.LayoutParams.MATCH_PARENT));

Объяснение: В вашем onCreateViewHolde, как только вы получите вид карты, получите ширину экрана, а затем установите соответствующий параметр макета для вида карты.

Кажется, это исправлено в 'com.android.support:recyclerview-v7:23.2.1'

Смотрите: RecyclerView wrap_content для дальнейшего обсуждения.

Просто установите новые параметры макета

view.setLayoutParams(new RecyclerView.LayoutParams(
    RecyclerView.LayoutParams.MATCH_PARENT,
    RecyclerView.LayoutParams.WRAP_CONTENT
));

Реализация по умолчанию заставляет использовать wrap_content в менеджере по умолчанию:

  @Override
public LayoutParams generateDefaultLayoutParams() {
    return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT);
}

Все, что вам нужно сделать, это переопределить этот метод в вашем LayoutManager следующим образом:

  @Override
public LayoutParams generateDefaultLayoutParams() {
    return new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT);
}

Это работает для меня

View view = inflator.inflate(R.layout.layout_item, ***null***, false);

Используйте card_view:contentPadding с отрицательным значением

<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:layout_width="match_parent"
    card_view:contentPadding="-4dp"
    card_view:cardElevation="0dp"
    android:layout_height="wrap_content">

У меня сработало

Заворачивать CardView в макете, который имеет ширину:match_parent