CardView layout_width = "match_parent" ne correspond pas à la largeur de RecyclerView parent

123

J'ai un fragment avec contient un RecyclerView avec 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" />

L'élément dans RecyclerView est un CardView également avec 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>

Je gonfle la vue de l'article comme ci-dessous:

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

Mais lorsque j'exécute l'application, CardView est rendu sous la forme wrap_content comme indiqué ci-dessous:

CartesBug

Notez que cela a été exécuté sur un émulateur, pas sur un appareil réel.

Est-ce que je fais quelque chose de mal ou est-ce un bug?

ProgrAmmar
la source
Lorsque vous gonflez CardView, fournissez-vous la vue parent avec un vrai paramètre?
nhaarman
Salut @NiekHaarman, veuillez voir la modification. J'ai ajouté le code gonflant. Et oui j'ai passé le vrai paramètre.
ProgrAmmar

Réponses:

291

Les documents pour inflate:

Gonflez une nouvelle hiérarchie de vues à partir de la ressource xml spécifiée. Lance InflateException s'il y a une erreur.

Paramètres ID de
ressource pour une ressource de mise en page XML à charger (par exemple, R.layout.main_page)
vue racine pour être le parent de la hiérarchie générée (si attachToRoot est vrai), ou simplement un objet qui fournit un ensemble de valeurs LayoutParams pour root de la hiérarchie renvoyée (si attachToRoot est faux.)
attachToRoot Si la hiérarchie gonflée doit être attachée au paramètre racine? Si la valeur est false, root n'est utilisé que pour créer la sous-classe correcte de LayoutParams pour la vue racine dans le XML. Renvoie la vue racine de la hiérarchie gonflée. Si root a été fourni et attachToRoot est vrai, il s'agit de root; sinon, c'est la racine du fichier XML gonflé.

Il est ici important de ne pas fournir vrai, mais ne fournir le parent:

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

Fournir la parentvue permet au gonfleur de savoir quels paramètres de disposition utiliser. Fournir le falseparamètre lui dit de ne pas encore l' attacher au parent. C'est ce que la RecyclerViewvolonté fera pour vous.

nhaarman
la source
4
La solution n'a pas fonctionné pour moi parce que le ListView l' layout_widthétait wrap_content. C'est bizarre car cela ne devrait pas affecter l'affichage de la liste! Donc, je crois comprendre que lorsque vous fournissez false comme paramètre au layoutinflater, le ListView ajoute les éléments de liste au ListView avec des paramètres de disposition correspondant au ListView lui-même! : 0
reubenjohn
1
pourriez-vous poster un peu plus de code, car je pense que je fais la même chose, mais en fait cela ne fonctionne pas
rodi
1
Je gonfle la façon dont votre suggestion et match_parent ne fonctionnent pas pour moi.
Zapnologica
3
Je pense que la compréhension correcte est que lorsque vous définissez attachToRoot sur false, vous devez fournir un objet avec la valeur LayoutParams définie. Cet objet n'est pas nécessairement le parent. "... simplement un objet qui fournit un ensemble de valeurs LayoutParams pour la racine de la hiérarchie retournée (si attachToRoot est faux.) ..." Mais je ne comprends pas pourquoi inflater ne peut pas lire les LayoutParams définis dans CardView mais ont besoin un autre paramètre d'objet pour l'informer?
hjchin
1
Si j'utilise la vue personnalisée, comment y faire face? Je veux direViewHolder onCreateViewHolder(...) { View v = new MyItemView(parent.getContext); return new ViewHolder(v); }
Kross
65

Utilisez RelativeLayout comme parent immédiat de CardView.

<RelativeLayout 
    android:layout_width="match_parent" ... >
    <CardView 
        android:layout_width="match_parent" ... >
    </CardView>
</RelativeLayout>
Ganesh Kanna
la source
Oui, cela a semblé fonctionner pour moi aussi. J'utilisais LinearLayout et la suggestion ci-dessus n'a pas fonctionné puisque je faisais déjà exactement cela (c'est-à-dire ne pas attacher à root, mais fournir un parent). Vous devez faire les deux RelativeLayout + sans attacher le parent, mais en en fournir un.
chubbsondubs
1
Cela fonctionne pour moi, mais je ne sais pas pourquoi cela peut résoudre le problème. Quelqu'un peut-il expliquer pourquoi?
Johnny
1
ça fait des siècles, android x est en production, toujours le bug n'est pas corrigé!
Muhammad Naderi
le moyen le plus simple.
Abdurahman Popal
J'ai eu un problème similaire et cela a fonctionné pour moi pour corriger la largeur de la vue de ma carte, mais j'ai un problème similaire avec la hauteur? Pouvez-vous me suggérer quelque chose pour cela également?
12

Cela a fonctionné pour moi,

 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
la source
6

La façon dont je l'ai fait est:

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

Explication: Dans votre onCreateViewHolde, une fois que vous obtenez la vue carte, obtenez la largeur de l'écran, puis définissez le paramètre de disposition en conséquence pour la vue carte.

Rahul
la source
1
veuillez l'améliorer légèrement. Il dit essentiellement "Essayez ceci"
Tiré
Explication ajoutée. Veuillez vérifier et si vous avez besoin d'aide supplémentaire, commentez ici.
Rahul
4

Définissez simplement de nouveaux paramètres de mise en page

view.setLayoutParams(new RecyclerView.LayoutParams(
    RecyclerView.LayoutParams.MATCH_PARENT,
    RecyclerView.LayoutParams.WRAP_CONTENT
));
Vlad
la source
J'ai trouvé cela utile dans onBindViewHolder () lors de l'utilisation d'une classe de vue personnalisée qui hérite de ConstraintLayout.
Rasmusob le
Ce n'est pas une bonne réponse car la marge définie pour la mise en page sera affectée.
Emi Raz le
4

L'implémentation par défaut force l'utilisation de wrap_content dans le gestionnaire de mise en page par défaut:

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

Tout ce que vous avez à faire est de remplacer cette méthode dans votre LayoutManager comme ceci:

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

Cela fonctionne pour moi

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

Utilisez card_view: contentPadding avec une valeur négative

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

Ça a marché pour moi

Vladimir Salguero
la source
-1

Enveloppez CardViewdans une mise en page qui a une largeur:match_parent

Samuel Moshie
la source