CardView layout_width = „match_parent” nie pasuje do nadrzędnej szerokości RecyclerView


123

Mam fragment zawierający RecyclerView z 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" />

Element w RecyclerView to CardView, również z 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>

Nadmuchuję widok przedmiotu, jak poniżej:

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

Ale kiedy uruchamiam aplikację, CardView jest renderowane jako wrap_content, jak pokazano poniżej:

CardsBug

Zauważ, że zostało to uruchomione na emulatorze, a nie na prawdziwym urządzeniu.

Czy robię coś źle, czy to błąd?


Czy podczas zawyżania CardView dostarczasz widok nadrzędny z prawdziwym parametrem?
nhaarman

Cześć @NiekHaarman, zobacz edycję. Dodałem kod inflacyjny. I tak, przekazałem prawdziwy parametr.
ProgrAmmar

Odpowiedzi:


291

Dokumenty dotyczące inflate:

Wypełnij nową hierarchię widoków z określonego zasobu xml. Zgłasza wyjątek InflateException, jeśli wystąpi błąd.

Parametry identyfikator
zasobu dla zasobu układu XML do załadowania (np. R.layout.main_page)
widok główny, który ma być elementem nadrzędnym wygenerowanej hierarchii (jeśli parametr attachToRoot ma wartość true), lub po prostu obiekt, który dostarcza zestaw wartości LayoutParams dla katalogu głównego zwracanej hierarchii (jeśli attachToRoot ma wartość false).
attachToRoot Czy zawyżona hierarchia powinna być dołączona do parametru root? Jeśli false, root jest używany tylko do tworzenia poprawnej podklasy LayoutParams dla widoku głównego w XML. Zwraca Widok główny zawyżonej hierarchii. Jeśli podano root i parametr AttachToRoot ma wartość true, to jest to root; w przeciwnym razie jest to katalog główny zawyżonego pliku XML.

Ważne jest, aby nie dostarczać prawda, ale nie dostarczają rodzica:

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

Dostarczenie parentwidoku pozwala inflaterowi wiedzieć, jakich parametrów układu użyć. Podanie falseparametru nakazuje mu jeszcze nie dołączać go do rodzica. To właśnie RecyclerViewzrobi dla ciebie wola.


4
Rozwiązanie nie zadziałało dla mnie, ponieważ ListView layout_widthbył wrap_content. To dziwne, ponieważ nie powinno to wpływać na widok listy! Rozumiem więc, że gdy podasz false jako parametr do layoutinflater, ListView dodaje elementy listy do ListView z parametrami układu pasującymi do samego ListView! : 0
reubenjohn

1
czy mógłbyś
napisać

1
Nadmuchuję, jak Twoja sugestia i match_parent nie działają dla mnie.
Zapnologica

3
Myślę, że prawidłowe zrozumienie jest takie, że kiedy ustawisz attachToRoot na false, musisz podać obiekt ze zdefiniowaną wartością LayoutParams. Ten obiekt niekoniecznie jest rodzicem. „... po prostu obiekt, który dostarcza zestaw wartości LayoutParams dla katalogu głównego zwracanej hierarchii (jeśli attachToRoot ma wartość false.)…” Ale nie rozumiem, dlaczego inflater nie może odczytać LayoutParams, które są zdefiniowane w CardView, ale potrzebują inny parametr obiektu informujący o tym?
hjchin

1
Jeśli używam widoku niestandardowego, jak sobie z tym poradzić? Mam na myśliViewHolder onCreateViewHolder(...) { View v = new MyItemView(parent.getContext); return new ViewHolder(v); }
Kross

66

Użyj RelativeLayout jako bezpośredniego elementu nadrzędnego CardView.

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

Tak, to wydawało się działać również dla mnie. Używałem LinearLayout i powyższa sugestia nie zadziałała, ponieważ już to robiłem (tj. Nie dołączałem do katalogu głównego, ale zapewniałem rodzica). Musisz zrobić oba RelativeLayout + nie dołączając rodzica, ale zapewniając jeden.
chubbsondubs

1
U mnie to działa, ale nie wiem, dlaczego to może rozwiązać problem. Czy ktoś może wyjaśnić dlaczego?
Johnny

1
minęły wieki, Android X jest w produkcji, nadal błąd nie został naprawiony!
Muhammad Naderi

najłatwiejszy sposób.
Abdurahman Popal

Miałem podobny problem i pomogło mi to poprawić szerokość widoku karty, ale mam podobny problem z wysokością? Czy możesz mi coś zasugerować?

12

To zadziałało dla mnie,

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

6

Sposób, w jaki to zrobiłem, to:

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

Objaśnienie: W swoim onCreateViewHolde po uzyskaniu widoku karty pobierz szerokość ekranu, a następnie ustaw odpowiednio parametr układu dla widoku karty.


1
proszę to nieco poprawić. Zasadniczo jest napisane „Spróbuj tego”
Drew

Dodano wyjaśnienie. Sprawdź i jeśli potrzebujesz dalszej pomocy, skomentuj tutaj.
Rahul


4

Po prostu ustaw nowe parametry układu

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

Zauważyłem, że robienie tego w onBindViewHolder () jest przydatne, gdy używam niestandardowej klasy widoku, która dziedziczy po ConstraintLayout.
Rasmusob,

To nie jest dobra odpowiedź, ponieważ wpłynie to na margines ustawiony w układzie.
Emi Raz

4

Domyślna implementacja wymusza użycie wrap_content w domyślnym menedżerze układu:

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

Wszystko, co musisz zrobić, to zastąpić tę metodę w swoim LayoutManager w następujący sposób:

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

2

To działa dla mnie

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

1

Użyj card_view: contentPadding z wartością ujemną

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

U mnie to zadziałało


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.