CardView layout_width = "match_parent" não corresponde à largura principal do RecyclerView

123

Eu tenho um fragmento com contém um RecyclerView com 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" />

O item no RecyclerView é um CardView também com 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>

Infle a visualização do item como abaixo:

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

Mas quando executo o aplicativo, o CardView é renderizado como wrap_content, como mostrado abaixo:

Cartões

Observe que isso foi executado no emulador, não em um dispositivo real.

Estou fazendo algo errado ou é um bug?

ProgrAmmar
fonte
Ao inflar o CardView, você está fornecendo à visualização pai um parâmetro verdadeiro?
Nhaarman
Olá @NiekHaarman, consulte a edição. Eu adicionei o código inflável. E sim, eu passei o parâmetro true.
ProgrAmmar

Respostas:

291

Os documentos para inflate:

Inflate uma nova hierarquia de exibição do recurso xml especificado. Lança InflateException se houver um erro.

Parâmetros ID do
recurso para um recurso de layout XML para carregar (por exemplo, R.layout.main_page) a
visualização raiz para ser o pai da hierarquia gerada (se attachToRoot for verdadeiro) ou simplesmente um objeto que fornece um conjunto de valores LayoutParams para raiz da hierarquia retornada (se attachToRoot for false.)
attachToRoot Se a hierarquia inflada deve ser anexada ao parâmetro raiz? Se falso, a raiz será usada apenas para criar a subclasse correta de LayoutParams para a visualização raiz no XML. Retorna A visão raiz da hierarquia inflada. Se a raiz foi fornecida e o attachToRoot for verdadeiro, isso é raiz; caso contrário, é a raiz do arquivo XML inflado.

É importante aqui para não fornecer verdade, mas não fornecer o pai:

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

Fornecer a parentvisualização permite que o inflador saiba quais parâmetros de layout usar. O fornecimento do falseparâmetro diz para ele ainda não o anexar ao pai. Isso é o que a RecyclerViewvontade fará por você.

nhaarman
fonte
4
A solução não funcionou para mim porque o ListView layout_widthera wrap_content. É estranho, porque isso não deve afetar a exibição da lista! Portanto, meu entendimento é que, quando você fornece false como parâmetro para o layoutinflater, o ListView adiciona os itens da lista ao ListView com parâmetros de layout que correspondem ao próprio ListView! : 0
reubenjohn
1
você pode postar um pouco de código mais, porque eu acho que estou fazendo o mesmo, mas na verdade ele não está funcionando
Rodi
1
Estou inflando como você sugestão e match_parent não está funcionando para mim.
Zapnologica
3
Eu acho que o entendimento correto é que, quando você define o attachToRoot como false, é necessário fornecer um objeto com o valor definido de LayoutParams. Esse objeto não é necessariamente o pai. "... simplesmente um objeto que fornece um conjunto de valores de LayoutParams para a raiz da hierarquia retornada (se attachToRoot é falso.) ..." Mas não entendo por que o inflater não pode ler os LayoutParams definidos no CardView, mas precisa outro parâmetro de objeto para informá-lo?
hjchin
1
Se eu usar a exibição personalizada, como lidar com isso? Quero dizerViewHolder onCreateViewHolder(...) { View v = new MyItemView(parent.getContext); return new ViewHolder(v); }
Kross
65

Use RelativeLayout como pai imediato do CardView.

<RelativeLayout 
    android:layout_width="match_parent" ... >
    <CardView 
        android:layout_width="match_parent" ... >
    </CardView>
</RelativeLayout>
Ganesh Kanna
fonte
Sim, isso parecia funcionar para mim também. Eu estava usando o LinearLayout e a sugestão acima não funcionou, pois eu já estava fazendo exatamente isso (ou seja, não estava anexando ao root, mas fornecendo um pai). Você precisa fazer o RelativeLayout + não anexando o pai, mas fornecendo um.
Chubbsondubs
1
Funciona para mim, mas não sei por que isso pode resolver o problema. Alguém pode explicar o porquê?
Johnny
1
Já faz muito tempo, o Android x está em produção, o bug ainda não foi corrigido!
Muhammad Naderi
a maneira mais fácil.
Abdurahman Popal 03/08/19
Eu tive um problema semelhante e isso funcionou para corrigir a largura da exibição do meu cartão, mas estou tendo um problema semelhante com a altura? Você pode me sugerir algo para isso também?
12

Isso funcionou para mim,

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

O jeito que eu fiz é:

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

Explicação: No onCreateViewHolde, depois de obter a visualização do cartão, obtenha a largura da tela e defina o parâmetro de layout adequadamente para a visualização do cartão.

Rahul
fonte
1
por favor melhore isso um pouco. Basicamente, diz "Tente isto"
Drew
Adicionado explicação. Verifique e, se precisar de mais ajuda, comente aqui.
Rahul
5

Isso parece estar corrigido em 'com.android.support:recyclerview-v7:23.2.1'

Veja: RecyclerView wrap_content para mais discussões.

speedynomads
fonte
4

Basta definir novos parâmetros de layout

view.setLayoutParams(new RecyclerView.LayoutParams(
    RecyclerView.LayoutParams.MATCH_PARENT,
    RecyclerView.LayoutParams.WRAP_CONTENT
));
Vlad
fonte
Eu achei isso útil no onBindViewHolder () útil ao usar uma classe de exibição personalizada que herda de ConstraintLayout.
Rasmusob 29/09/17
Não é uma boa resposta porque a margem que foi definida para o layout será afetada.
Emi Raz
4

A implementação padrão força o uso de wrap_content no gerenciador de layout padrão:

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

Tudo o que você precisa fazer é substituir esse método no seu LayoutManager da seguinte maneira:

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

Isso funciona para mim

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

Use card_view: contentPadding com um valor negativo

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

Funcionou para mim

Vladimir Salguero
fonte
-1

Quebrar CardViewem um layout que tenha largura:match_parent

Samuel Moshie
fonte