Rand / Polsterung im letzten Kind in RecyclerView

126

Ich versuche, Padding / Margin Bottom in der letzten Reihe und Padding / Margin Top in der ersten Reihe hinzuzufügen. Ich kann es in der Item-XML nicht tun, da es alle meine Childs betreffen würde.

Ich habe Header und Childs in meinem RecyclerView-Adapter, daher kann ich den nicht verwenden

   android:padding="4dp"
   android:clipToPadding="false"

Ich muss es einzeln in der letzten ersten Zeile jedes Headers verwenden

Roter Adler
quelle
Verwenden Sie wie folgt: <android.support.v7.widget.RecyclerView android: id = "@ + id / list" android: paddingBottom = "5dp" android: layout_width = "match_parent" android: layout_height = "wrap_content" />
Pankaj Arora
Sie können den Abstand und den Rand in onBindViewHolder ändern und dann setIsRecyclable (false) für den Ansichtsinhaber
aufrufen

Antworten:

9

Ich benutze dies in Kotlin

override fun onBindViewHolder(holder: RecyclerView.ViewHolder(view), position: Int) {
    if (position == itemsList.lastIndex){
        val params = holder.itemView.layoutParams as FrameLayout.LayoutParams
        params.bottomMargin = 100
        holder.itemView.layoutParams = params
    }else{
        val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
        params.bottomMargin = 0
        holder.itemView.layoutParams = params
    }
  //other codes ...
}
Radesh
quelle
232

Dieses Problem ist noch einfacher zu lösen. Sie können das erforderliche Auffüllen auf sich RecylerViewselbst anwenden und clipToPaddingauf false setzen. Andernfalls wird das Auffüllen Ihren Bildlaufbereich abschneiden. Hier ist ein Beispiel

<android.support.v7.widget.RecyclerView
    android:padding="4dp"
    android:clipToPadding="false"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Siehe die Polsterung fügt 4dp auf allen Seiten hinzu, einschließlich oben und unten. Dann stellt der Parameter clipToPadding sicher, dass Ihre untergeordneten Elemente nicht abgeschnitten werden. Fügen Sie jetzt 4dpan allen Seiten Polster für Ihre Kinderartikel hinzu, und schon kann es losgehen. Insgesamt erhalten Sie 8dp Polsterung an den Seiten und zwischen den Elementen.

Subin Sebastian
quelle
Ja, so mache ich das normalerweise, aber mein RecyclerView besteht aus Headern und jeder Header hat seine eigenen Childs. Deshalb muss ich ihn programmgesteuert nur auf die letzte und erste Zeile jedes Headers setzen
RedEagle
Nicht sicher ob ich verstehe. Wie hängt dies mit den Headern in RecyclerView zusammen? Möchten Sie, dass die Header nicht aufgefüllt werden? Selbst wenn dies der Fall ist, können Sie mit derselben Lösung die linke und rechte Polsterung entfernen.
Subin Sebastian
Ich habe Überschriften und jede Überschrift hat eine unspezifische Anzahl von untergeordneten Elementen. Daher möchte ich beim letzten untergeordneten Element jeder Überschrift die obere Auffüllung / den oberen Rand und das erste untergeordnete und die untere Auffüllung / den unteren Rand hinzufügen.
RedEagle
Die einzige Idee, die ich hatte, war, den oberen und unteren Rand in das Layout meines Headers zu setzen, aber ich fragte mich, ob es einen intelligenteren Weg gibt, dies zu erreichen
RedEagle
In diesem Fall können Sie nach Ihrem letzten Kind einfach einen gefälschten Artikel in die RecyclerView einfügen. Das ist der einfachste, wenn nicht der klügste Weg, dies zu erreichen. :)
Subin Sebastian
82

Anstatt sowohl den oberen als auch den unteren Elementen Auffüllungen hinzuzufügen, können Sie die Auffüllungen einfach oben und unten in Ihrer RecyclerView hinzufügen und das clipToPaddingAttribut auf festlegen false.

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:paddingTop="8dp"
    android:paddingBottom="8dp" />
Collins Abitekaniza
quelle
Das ist die einfache Lösung, aber ich habe Header und Childs in meinem RecyclerView, so dass ich es nicht verwenden kann
RedEagle
@RedEagle Versuchen Sie zu sehen, ob Sie den gewünschten Effekt erzielen, aber ich bin sicher, dass er funktioniert.
Collins Abitekaniza
1
Diese Lösung ist besser als die Item Decoration. Wenn ich ListAdapter verwende und eine andere Liste sende und das letzte Element der vorherigen Liste seine Position nicht geändert hat, aber danach neue Elemente hinzugefügt wurden, behält das erstere seine untere Auffüllung bei, obwohl es nicht das letzte Element in der Liste ist Mehr.
Ana Koridze
38

Verwenden Sie ItemDecoration:

private class SpacesItemDecoration extends RecyclerView.ItemDecoration {
    private int space;

    public SpacesItemDecoration(int space) {
        this.space = space;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view);
        boolean isLast = position == state.getItemCount()-1;
        if(isLast){
            outRect.bottom = space;
            outRect.top = 0; //don't forget about recycling...
        }
        if(position == 0){
            outRect.top = space;
            // don't recycle bottom if first item is also last
            // should keep bottom padding set above
            if(!isLast)
                outRect.bottom = 0;
        }
    }
}

und

//8dp as px
int space = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,
            getResources().getDisplayMetrics()); // calculated
//int space = getResources().getDimensionPixelSize(
//    R.dimen.list_item_padding_vertical); // from resources
recyclerView.addItemDecoration(new SpacesItemDecoration(space));
snachmsm
quelle
1
Hey, es scheint nicht mehr so, als würde RecyclerView.ItemDecoration die Ressourcenklasse mehr abrufen. Ich habe sie nur als Argument im Konstruktor hinzugefügt.
Krtko
2
Goog-Lösung! Mit umgekehrter Layoutunterstützung
Miha_x64
2
Diese Antwort muss positiv bewertet werden! Obwohl Subin Sebastians Antwort gut funktioniert, sind die Leerzeichen bei ItemDecoration nicht gleich.
iroiroys
1
Nach dem Einfügen entfernender Elemente werden jedoch nicht für alle Elemente Offsets neu
gezeichnet
kann wahr sein, da notifyItemInserted/ Removednur einen Gegenstand zeichnet / Gegenstand entfernt und säubert, so Viewdass alle anderen Kinder unberührt bleiben. Wenn beispielsweise ein Element zuerst in der Liste aufgeführt ist (mit oberster Auffüllung gezeichnet) und wir ein neues Element nach oben hinzufügen, wird das zuvor zuerst-aktuell-zweite Element weiterhin oben aufgefüllt. Eine einfache Lösung ist das Aufrufen notifyDataSetChanged(erneutes Zeichnen erzwingen) Alle ...), komplexere, benötigen eine Logik zum Erkennen des Elements, das sich an der ersten und / oder letzten Position befand, verschoben und dann aufgerufen wurdenotifyItemChanged(newPositionOfOldFirstAndOrLastItem)
snachmsm
28
<android.support.v7.widget.RecyclerView
    android:id="@+id/rv_tpf"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clipToPadding="false"
    android:paddingBottom="100dp" />

Fügen Sie android:clipToPadding="false"und android:paddingBottom="100dp"in Ihrem Recycling-Überblick hinzu.

Darshan Patel
quelle
2
Genial! Das ist perfekt
KevinB
16

Fügen Sie android: clipToPadding = "false" und android: paddingBottom = "65dp" in Ihre Recyclingansicht ein. Wenn Sie die Fab-Menüschaltfläche und Aktionen für die Recycler-Ansichtszelle verwenden.

<androidx.recyclerview.widget.RecyclerView
      android:id="@+id/dinner_recycler_view"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:clipToPadding="false"
      android:paddingBottom="65dp"/>
Yogesh Shinde
quelle
3

Aus irgendeinem Grund clipToPadding=falsefunktioniert die alte Lösung bei mir nicht. Also habe ich eine ItemDecoration hinzugefügt

https://gist.github.com/kassim/582888fa5960791264fc92bc41fb6bcf

public class BottomPaddingDecoration extends RecyclerView.ItemDecoration {
    private final int bottomPadding;

    public BottomPaddingDecoration(int bottomPadding) {
        this.bottomPadding = bottomPadding;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
        if (position == parent.getAdapter().getItemCount() - 1) {
            outRect.set(0, 0, 0, bottomPadding);
        }
    }
}
kassim
quelle
1

Ich habe erstaunliche Antwort @snachmsm Antwort zum Besseren geändert und gebe Ihnen eine Idee, wie man richtig verwendet

public class SpacesItemDecoration extends DividerItemDecoration {
    private int space;

    public SpacesItemDecoration(Context clContext,int oriantation,int space) {
        super(clContext,oriantation);
        this.space = space;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect,view,parent,state);
        int position = parent.getChildAdapterPosition(view);
        boolean isLast = position == state.getItemCount()-1;
        if(isLast){
            outRect.bottom = space;
            outRect.top = 0; //don't forget about recycling...
        }
       /* if(position == 0){
            outRect.top = space;
            // don't recycle bottom if first item is also last
            // should keep bottom padding set above
            if(!isLast)
                outRect.bottom = 0;
        }*/
    }
}
Sourav Pandit
quelle