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

123

У меня есть фрагмент, содержащий 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

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

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

ProgrAmmar
источник
Предоставляете ли вы родительскому представлению истинный параметр при наполнении CardView?
nhaarman 01
Привет, @NiekHaarman, пожалуйста, посмотрите правку. Я добавил код надувания. И да, я передал верный параметр.
ProgrAmmar 01

Ответы:

291

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

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

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

Здесь важно , чтобы не поставить так, но ничего поставить родитель:

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

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

nhaarman
источник
4
Решение не сработало для меня, потому что ListView layout_widthбыл wrap_content. Это странно, потому что это не должно влиять на представление списка! Насколько я понимаю, когда вы предоставляете false в качестве параметра layoutinflater, ListView добавляет элементы списка в ListView с параметрами макета, соответствующими самому ListView! : 0
reubenjohn
1
не могли бы вы опубликовать еще немного кода, потому что я думаю, что делаю то же самое, но на самом деле он не работает
Роди
1
Я раздуваю, как вы предлагаете и match_parent не работает для меня.
Zapnologica
3
Я думаю, что правильное понимание состоит в том, что когда вы устанавливаете для attachToRoot значение false, вам необходимо предоставить объект с определенным значением LayoutParams. Этот объект не обязательно является родительским. «... просто объект, который предоставляет набор значений LayoutParams для корня возвращаемой иерархии (если attachToRoot имеет значение false.) ...» Но я не понимаю, почему inflater не может прочитать LayoutParams, который определен в CardView, но ему нужно другой параметр объекта, чтобы сообщить об этом?
hjchin
1
Если я использую настраиваемый вид, как с этим бороться? Я имею в видуViewHolder onCreateViewHolder(...) { View v = new MyItemView(parent.getContext); return new ViewHolder(v); }
Кросс
65

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

<RelativeLayout 
    android:layout_width="match_parent" ... >
    <CardView 
        android:layout_width="match_parent" ... >
    </CardView>
</RelativeLayout>
Ганеш Канна
источник
Да, это тоже сработало для меня. Я использовал LinearLayout, и приведенное выше предложение не сработало, поскольку я уже делал именно это (то есть не подключался к root, а предоставлял родителя). Вы должны сделать как RelativeLayout +, не прикрепляя родителя, но предоставляя его.
chubbsondubs
1
У меня это работает, но я не знаю, почему это может решить проблему. Кто-нибудь может объяснить, почему?
Johnny
1
прошло много времени, android x находится в разработке, но ошибка не исправлена!
Мухаммад Надери
самый простой способ.
Абдурахман Попал
У меня была аналогичная проблема, и это помогло мне исправить ширину представления моей карты, но у меня аналогичная проблема с высотой? Можете ли вы мне что-то предложить?
12

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

 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);
anurag_dake
источник
6

Как я это сделал:

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

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

Рахул
источник
1
пожалуйста, улучшите это немного. По сути, там написано: «Попробуйте это»
Дрю
Добавлено объяснение. Пожалуйста, проверьте и, если вам нужна дополнительная помощь, прокомментируйте здесь.
Рахул
5

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

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

speedynomads
источник
4

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

view.setLayoutParams(new RecyclerView.LayoutParams(
    RecyclerView.LayoutParams.MATCH_PARENT,
    RecyclerView.LayoutParams.WRAP_CONTENT
));
Влад
источник
Я обнаружил, что делать это в onBindViewHolder () полезно при использовании настраиваемого класса представления, который наследуется от ConstraintLayout.
Расмусоб
Это не лучший ответ, потому что это повлияет на маржу, установленную для макета.
Эми Раз,
4

Реализация по умолчанию заставляет использовать 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);
}
issamux
источник
2

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

View view = inflator.inflate(R.layout.layout_item, ***null***, false);
DiRiNoiD
источник
1

Используйте 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">

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

Владимир Сальгеро
источник
-1

Оберните CardViewмакет шириной:match_parent

Сэмюэл Моши
источник