Marge / remplissage dans le dernier enfant dans RecyclerView

126

J'essaie d'ajouter Padding / Margin Bottom dans la dernière ligne et Padding / Margin Top dans la première ligne. Je ne peux pas le faire dans l'élément xml car cela affecterait tous mes enfants.

J'ai des en-têtes et des enfants dans mon adaptateur RecyclerView, je ne peux donc pas utiliser le

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

Je dois l'utiliser individuellement sur la dernière première ligne de chaque en-tête

Aigle Rouge
la source
Utilisez comme ceci: <android.support.v7.widget.RecyclerView android: id = "@ + id / list" android: paddingBottom = "5dp" android: layout_width = "match_parent" android: layout_height = "wrap_content" />
Pankaj Arora
Vous pouvez modifier le remplissage et la marge dans onBindViewHolder, puis appeler setIsRecyclable (false) sur le support de vue
user3425867

Réponses:

9

J'utilise ça dans 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
la source
233

Ce problème est encore plus facile à résoudre. Vous pouvez appliquer le remplissage nécessaire à RecylerViewlui - même et définir clipToPaddingsur false, sinon, le remplissage coupera votre zone de défilement. Voici un exemple

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

Voir le rembourrage ajoutera 4dp sur tous les côtés, y compris le haut et le bas. Ensuite, le paramètre clipToPadding s'assure que vos éléments enfants ne sont pas coupés. Maintenant, ajoutez un 4dprembourrage de tous les côtés pour vos articles enfants, et vous êtes prêt à partir. Au total, vous obtenez un rembourrage de 8dp sur les côtés et entre les éléments.

Subin Sebastian
la source
Oui, c'est comme ça que je le fais habituellement, mais mon RecyclerView est composé d'en-têtes et chaque en-tête a ses propres enfants, c'est pourquoi je dois le définir par programme sur la dernière et la première ligne de chaque en-tête uniquement
RedEagle
Pas sûr que je comprenne. Comment cela est-il lié aux en-têtes à l'intérieur de RecyclerView? Voulez-vous que les en-têtes n'aient pas de remplissage? Même si tel est le cas, vous pouvez vous débarrasser du rembourrage gauche et droit en utilisant la même solution.
Subin Sebastian
J'ai des en-têtes et chaque en-tête a un nombre d'enfants non spécifique, je veux donc ajouter un rembourrage / marge supérieur et le premier enfant et un rembourrage / marge inférieur au dernier enfant de chaque en-tête.
RedEagle
La seule idée que j'avais était de définir une marge supérieure et inférieure dans la disposition de mon en-tête, mais je me demandais s'il y avait un moyen plus intelligent de le
réaliser
Dans ce cas, vous pouvez simplement ajouter un faux article dans le RecyclerView après votre dernier enfant. C'est le moyen le plus simple, sinon le plus intelligent, d'y parvenir. :)
Subin Sebastian
82

Au lieu d'ajouter un remplissage aux éléments du haut et du bas, vous pouvez simplement ajouter le remplissage en haut et en bas de votre RecyclerView et définir l' clipToPaddingattribut sur 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
la source
C'est la solution simple, mais j'ai des en-têtes et des enfants dans mon RecyclerView, donc je ne peux pas l'utiliser
RedEagle
@RedEagle Essayez de voir si vous obtenez l'effet souhaité, mais je suis sûr que cela fonctionne.
Collins Abitekaniza
1
Cette solution est meilleure que celle de la décoration d'objets. Lorsque j'utilise ListAdapter et que je soumets une liste différente, si le dernier élément de la liste précédente n'a pas changé sa position mais que de nouveaux éléments ont été ajoutés après lui, le premier conservera son remplissage inférieur même s'il ne s'agit pas du dernier élément de la liste. plus.
Ana Koridze
38

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

et

//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
la source
1
Hé, il ne semble pas que RecyclerView.ItemDecoration récupère plus la classe de ressources, je viens de l'ajouter comme argument dans le constructeur.
Krtko
2
Solution goog! Avec prise en charge de la mise en page inversée: gist.github.com/Miha-x64/4e8754e72a1e65e3ca742744ea501f16
Miha_x64
2
cette réponse doit être votée pour! Bien que la réponse de Subin Sebastian fonctionne bien, cependant, avec ItemDecoration, les espaces ne sont pas égaux.
iroiroys
1
mais après avoir inséré des éléments supprimés, il ne redessine pas les décalages pour tous les éléments
user924
peut être vrai, car notifyItemInserted/ Removeddessinera un seul élément / supprimera l'élément et nettoiera tout en Viewlaissant tous les autres enfants intacts. Par exemple, lorsqu'un élément est le premier sur la liste (dessiné avec un rembourrage supérieur) et que nous en ajoutons un nouveau en haut, alors l'élément précédemment premier-actuellement-deuxième sera toujours rempli en haut ... une solution facile est d'appeler notifyDataSetChanged(forcer le redessiner all ...), plus complexe nécessite une logique pour reconnaître cet élément, qui était en première et / ou dernière position, déplacé puis appelnotifyItemChanged(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" />

Ajoutez android:clipToPadding="false"et android:paddingBottom="100dp"dans votre vue de recyclage.

darshan patel
la source
2
Impressionnant! C'est parfait
KevinB
16

Ajoutez android: clipToPadding = "false" et android: paddingBottom = "65dp" dans votre vue de recyclage. Si vous utilisez le bouton de menu fab et les actions sur la cellule de vue du recycleur.

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

Pour une raison quelconque, l'ancienne clipToPadding=falsesolution ne fonctionne pas pour moi. J'ai donc ajouté un ItemDecoration

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

J'ai modifié la réponse incroyable @snachmsm pour mieux et vous donner une idée de la façon de l'utiliser correctement

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