Voici un exemple de la manière dont cela aurait pu être fait auparavant dans la classe ListView
, en utilisant les paramètres diviseur et dividerHeight:
<ListView
Android:id="@+id/activity_home_list_view"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:divider="@Android:color/transparent"
Android:dividerHeight="8dp"/>
Cependant, je ne vois pas une telle possibilité dans la classe RecyclerView
.
<Android.support.v7.widget.RecyclerView
Android:id="@+id/activity_home_recycler_view"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:scrollbars="vertical"/>
Dans ce cas, est-il possible de définir des marges et/ou d'ajouter une vue de division personnalisée directement dans la présentation d'un élément de liste ou existe-t-il un meilleur moyen d'atteindre mon objectif?
Mise à jour d'octobre 2016
La version 25.0.0 de Android Bibliothèque de support introduite DividerItemDecoration
classe:
DividerItemDecoration est un RecyclerView.ItemDecoration qui peut être utilisé comme séparateur entre les éléments d'un
LinearLayoutManager
. Il supporte les deux orientationsHORIZONTAL
etVERTICAL
.
Usage:
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
layoutManager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);
Réponse précédente
Certaines réponses utilisent des méthodes devenues obsolètes depuis ou ne donnent pas une solution complète. J'ai donc essayé de faire un résumé bref et à jour.
Contrairement à ListView
, la classe RecyclerView
n'a aucun paramètre lié au diviseur. Au lieu de cela, vous devez étendre ItemDecoration
, une classe interne de RecyclerView
:
ItemDecoration
permet à l'application d'ajouter un dessin spécial et un décalage de présentation à des vues d'élément spécifiques à partir du jeu de données de l'adaptateur. Cela peut être utile pour tracer des séparations entre les éléments, les surbrillances, les limites de regroupement visuel, etc.Tous les
ItemDecorations
sont dessinés dans l'ordre dans lequel ils ont été ajoutés, avant les vues d'élément (dansonDraw()
) et après les éléments (dans onDrawOver (Canvas
,RecyclerView
,RecyclerView.State)
.
Vertical
espacement ItemDecoration
Étendre ItemDecoration
, ajouter un constructeur personnalisé qui prend de la place height
en tant que paramètre et remplacer la méthode getItemOffsets()
:
public class VerticalSpaceItemDecoration extends RecyclerView.ItemDecoration {
private final int verticalSpaceHeight;
public VerticalSpaceItemDecoration(int verticalSpaceHeight) {
this.verticalSpaceHeight = verticalSpaceHeight;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
outRect.bottom = verticalSpaceHeight;
}
}
Si vous ne souhaitez pas insérer d'espace sous le dernier élément, ajoutez la condition suivante:
if (parent.getChildAdapterPosition(view) != parent.getAdapter().getItemCount() - 1) {
outRect.bottom = verticalSpaceHeight;
}
Remarque: vous pouvez également modifier les propriétés outRect.top
, outRect.left
et outRect.right
pour l'effet souhaité.
ItemDecoration
Étendre la méthode ItemDecoration
et la remplacer par la méthode onDraw()
:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{Android.R.attr.listDivider};
private Drawable divider;
/**
* Default divider will be used
*/
public DividerItemDecoration(Context context) {
final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
divider = styledAttributes.getDrawable(0);
styledAttributes.recycle();
}
/**
* Custom divider will be used
*/
public DividerItemDecoration(Context context, int resId) {
divider = ContextCompat.getDrawable(context, resId);
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top + divider.getIntrinsicHeight();
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
}
Vous pouvez appeler le premier constructeur qui utilise les attributs de diviseur Android par défaut ou le second qui utilise votre propre dessin, par exemple drawable/divider.xml.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:shape="rectangle">
<size Android:height="1dp" />
<solid Android:color="#ff992900" />
</shape>
Remarque: si vous souhaitez que le séparateur soit tracé sur vos éléments, remplacez la méthode onDrawOver()
.
Pour utiliser votre nouvelle classe, ajoutez VerticalSpaceItemDecoration
ou DividerSpaceItemDecoration
à RecyclerView
, par exemple dans la méthode onCreateView()
de votre fragment:
private static final int VERTICAL_ITEM_SPACE = 48;
private RecyclerView recyclerView;
private LinearLayoutManager linearLayoutManager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_feed, container, false);
recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_home_recycler_view);
linearLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(linearLayoutManager);
//add ItemDecoration
recyclerView.addItemDecoration(new VerticalSpaceItemDecoration(VERTICAL_ITEM_SPACE));
//or
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity()));
//or
recyclerView.addItemDecoration(
new DividerItemDecoration(getActivity(), R.drawable.divider));
recyclerView.setAdapter(...);
return rootView;
}
Il y a aussi bibliothèque de Lucas Rocha qui est supposé simplifier le processus de décoration d'objets. Je n'ai pas encore essayé.
Parmi ses fonctionnalités sont:
Il suffit d'ajouter
recyclerView.addItemDecoration(new DividerItemDecoration(getContext(),
DividerItemDecoration.VERTICAL));
Aussi, vous devrez peut-être ajouter la dépendancecompile 'com.Android.support:recyclerview-v7:27.1.0'
EDIT:
Pour le personnaliser un peu, vous pouvez ajouter un dessin personnalisable:
DividerItemDecoration itemDecorator = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
itemDecorator.setDrawable(ContextCompat.getDrawable(getContext(), R.drawable.divider));
Vous êtes libre d'utiliser n'importe quel dessin personnalisable, par exemple:
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:shape="rectangle">
<solid Android:color="@color/colorPrimary"/>
<size Android:height="0.5dp"/>
</shape>
Puis-je attirer votre attention sur ce fichier particulier sur Github par Alex Fu: https://Gist.github.com/alexfu/0f464fc3742f134ccd1e
Il s’agit du fichier exemple DividerItemDecoration.Java "tiré directement des démonstrations de support". ( https://plus.google.com/103498612790395592106/posts/VVEB3m7NkSS )
J'ai pu obtenir des lignes de séparation agréablement après l'importation de ce fichier dans mon projet et l'ajouter en tant que décoration d'élément à la vue du recycleur.
Voici à quoi ressemble onCreateView dans mon fragment contenant Recyclerview:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_recycler_view, container, false);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view);
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
return rootView;
}
Je suis sûr que d'autres styles peuvent être créés, mais c'est un point de départ. :)
Simple ItemDecoration
implémentation pour des espaces égaux entre tous les éléments.
public 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) {
outRect.left = space;
outRect.right = space;
outRect.bottom = space;
// Add top margin only for the first item to avoid double space between items
if(parent.getChildAdapterPosition(view) == 0) {
outRect.top = space;
}
}
}
Le plus simple est de définir la couleur de fond pour RecyclerView et une couleur de fond différente pour les éléments. Voici un exemple ...
<Android.support.v7.widget.RecyclerView
Android:background="#ECEFF1"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:scrollbars="vertical"/>
et l'élément TextView (il peut être n'importe quoi) avec la marge inférieure "x" dp ou px.
<TextView
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_marginBottom="1dp"
Android:background="#FFFFFF"/>
Le résultat ...
Je pense que l'utilisation d'un simple diviseur vous aidera
Pour ajouter un séparateur à chaque élément:
1- Ajoutez ceci à un répertoire dessinable line_divider.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:shape="rectangle">
<size
Android:width="1dp"
Android:height="1dp" />
<solid Android:color="#999999" />
</shape>
2- Créer une classe SimpleDividerItemDecoration
J'ai utilisé cet exemple pour définir cette classe:
https://Gist.github.com/polbins/e37206fbc444207c0e92
package com.example.myapp;
import Android.content.Context;
import Android.content.res.Resources;
import Android.graphics.Canvas;
import Android.graphics.drawable.Drawable;
import Android.support.v7.widget.RecyclerView;
import Android.view.View;
import com.example.myapp.R;
public class SimpleDividerItemDecoration extends RecyclerView.ItemDecoration{
private Drawable mDivider;
public SimpleDividerItemDecoration(Resources resources) {
mDivider = resources.getDrawable(R.drawable.line_divider);
}
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
}
3- Dans l'activité ou le fragment qui utilise RecyclerView, dans onCreateView, ajoutez ceci:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
RecyclerView myRecyclerView = (RecyclerView) layout.findViewById(R.id.my_recycler_view);
myRecyclerView.addItemDecoration(new SimpleDividerItemDecoration(getResources()));
....
}
4- Pour ajouter un espacement entre les éléments
il vous suffit d’ajouter une propriété de remplissage à la vue de votre article
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent" Android:layout_height="match_parent"
Android:padding="4dp"
>
..... item structure
</RelativeLayout>
Comme je l'ai défini ItemAnimators
. Le ItemDecorator
n'entre pas et ne sort pas avec l'animation.
J'ai simplement fini par avoir une ligne de vue dans mon fichier de présentation de vue d'article de chaque article. Cela a résolu mon cas. DividerItemDecoration
senti être trop de sorcellerie pour un simple diviseur.
<View
Android:layout_width="match_parent"
Android:layout_height="1px"
Android:layout_marginLeft="5dp"
Android:layout_marginRight="5dp"
Android:background="@color/lt_gray"/>
C'est simple, vous n'avez pas besoin d'un code aussi compliqué
DividerItemDecoration divider = new
DividerItemDecoration(mRVMovieReview.getContext(),
DividerItemDecoration.VERTICAL);
divider.setDrawable(
ContextCompat.getDrawable(getBaseContext(), R.drawable.line_divider)
);
mRVMovieReview.addItemDecoration(divider);
Ajoutez ceci dans votre dessin: line_divider.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:shape="rectangle">
<size Android:height="1dp" />
<solid Android:color="@Android:color/black" />
</shape>
Puisqu'il n'y a pas de bonne façon de mettre en œuvre cela à l'aide de Material Design, j'ai juste fait le truc suivant pour ajouter directement un séparateur à l'élément de la liste:
<View
Android:layout_width="match_parent"
Android:layout_height="1dp"
Android:background="@color/dividerColor"/>
Avec la bibliothèque de support v25.0.0, une implémentation par défaut des séparateurs horizontaux et verticaux de base est enfin disponible!
https://developer.Android.com/reference/Android/support/v7/widget/DividerItemDecoration.html
Si quelqu'un cherche à ne faire qu'ajouter, disons, un espacement de 10dp entre les éléments, vous pouvez le faire en définissant un dessin sur DividerItemDecoration
:
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
recyclerView.getContext(),
layoutManager.getOrientation()
);
dividerItemDecoration.setDrawable(
ContextCompat.getDrawable(getContext(), R.drawable.divider_10dp)
);
Où divider_10dp
est une ressource pouvant être dessinée contenant:
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android" Android:shape="rectangle">
<size Android:height="10dp"/>
<solid Android:color="@Android:color/transparent"/>
</shape>
Pour ceux qui recherchent juste espaces entre les éléments dans la RecyclerView
voyez mon approche où vous obtenez des espaces égaux entre tous les éléments, sauf dans les premier et dernier éléments où j'ai donné un rembourrage plus important. J'applique uniquement le remplissage à gauche/droite en horizontal LayoutManager
et en haut/en bas à la verticale LayoutManager
.
public class PaddingItemDecoration extends RecyclerView.ItemDecoration {
private int mPaddingPx;
private int mPaddingEdgesPx;
public PaddingItemDecoration(Activity activity) {
final Resources resources = activity.getResources();
mPaddingPx = (int) resources.getDimension(R.dimen.paddingItemDecorationDefault);
mPaddingEdgesPx = (int) resources.getDimension(R.dimen.paddingItemDecorationEdge);
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
final int itemPosition = parent.getChildAdapterPosition(view);
if (itemPosition == RecyclerView.NO_POSITION) {
return;
}
int orientation = getOrientation(parent);
final int itemCount = state.getItemCount();
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
/** HORIZONTAL */
if (orientation == LinearLayoutManager.HORIZONTAL) {
/** all positions */
left = mPaddingPx;
right = mPaddingPx;
/** first position */
if (itemPosition == 0) {
left += mPaddingEdgesPx;
}
/** last position */
else if (itemCount > 0 && itemPosition == itemCount - 1) {
right += mPaddingEdgesPx;
}
}
/** VERTICAL */
else {
/** all positions */
top = mPaddingPx;
bottom = mPaddingPx;
/** first position */
if (itemPosition == 0) {
top += mPaddingEdgesPx;
}
/** last position */
else if (itemCount > 0 && itemPosition == itemCount - 1) {
bottom += mPaddingEdgesPx;
}
}
if (!isReverseLayout(parent)) {
outRect.set(left, top, right, bottom);
} else {
outRect.set(right, bottom, left, top);
}
}
private boolean isReverseLayout(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getReverseLayout();
} else {
throw new IllegalStateException("PaddingItemDecoration can only be used with a LinearLayoutManager.");
}
}
private int getOrientation(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getOrientation();
} else {
throw new IllegalStateException("PaddingItemDecoration can only be used with a LinearLayoutManager.");
}
}
}
dimens.xml
<resources>
<dimen name="paddingItemDecorationDefault">10dp</dimen>
<dimen name="paddingItemDecorationEdge">20dp</dimen>
</resources>
Ajoutez simplement un arrière-plan à la mise en page de votre article de recycleur comme suit
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:background="@drawable/shape_border"
Android:gravity="center"
Android:orientation="horizontal"
Android:padding="5dp">
<ImageView
Android:id="@+id/imageViewContactLogo"
Android:layout_width="60dp"
Android:layout_height="60dp"
Android:layout_marginRight="10dp"
Android:src="@drawable/ic_user" />
<LinearLayout
Android:id="@+id/linearLayout"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_weight="0.92"
Android:gravity="center|start"
Android:orientation="vertical">
<TextView
Android:id="@+id/textViewContactName"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:singleLine="true"
Android:text="Large Text"
Android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
Android:id="@+id/textViewStatusOrNumber"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginTop="5dp"
Android:singleLine="true"
Android:text=""
Android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
<TextView
Android:id="@+id/textViewUnreadCount"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginRight="10dp"
Android:padding="5dp"
Android:text=""
Android:textAppearance="?android:attr/textAppearanceMedium"
Android:textColor="@color/red"
Android:textSize="22sp" />
<Button
Android:id="@+id/buttonInvite"
Android:layout_width="54dp"
Android:layout_height="wrap_content"
Android:background="@drawable/ic_add_friend" />
</LinearLayout>
Créez le fichier shape_border.xml suivant dans un dossier pouvant être dessiné
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:shape="rectangle" >
<gradient
Android:angle="270"
Android:centerColor="@Android:color/transparent"
Android:centerX="0.01"
Android:startColor="#000" />
</shape>
Voici le résultat final - un RecyclerView avec diviseur.
En réalité, cela ne résout pas le problème, mais en guise de solution de contournement temporaire, vous pouvez définir la propriété seCompatPadding sur la carte dans votre présentation XML afin qu'elle soit identique à celle des versions antérieures à Lollipop.
card_view:cardUseCompatPadding="true"
Ajoutez une marge à votre vue, cela a fonctionné pour moi.
Android:layout_marginTop="10dp"
Si vous souhaitez simplement ajouter espacement égal et que vous souhaitez le faire dans XML, définissez simplement padding
sur votre RecyclerView
et une quantité égale de layoutMargin
à l'élément que vous gonflez dans votre RecyclerView
, et laissez la couleur d'arrière-plan déterminer la couleur d'espacement.
J'ai créé le DividerItemDecoration à partir d'un ancien Gist et je l'ai simplifié pour s'adapter à mon cas d'utilisation. Je l'ai également modifié pour dessiner les séparateurs tels qu'ils sont dessinés dans ListView, y compris un séparateur après le dernier élément de la liste. Ceci gérera également les animations verticales ItemAnimator:
1) Ajoutez cette classe à votre projet:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{Android.R.attr.listDivider};
private Drawable divider;
public DividerItemDecoration(Context context) {
try {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
divider = a.getDrawable(0);
a.recycle();
} catch (Resources.NotFoundException e) {
// TODO Log or handle as necessary.
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (divider == null) return;
if (parent.getChildAdapterPosition(view) < 1) return;
if (getOrientation(parent) == LinearLayoutManager.VERTICAL)
outRect.top = divider.getIntrinsicHeight();
else
throw new IllegalArgumentException("Only usable with vertical lists");
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (divider == null) {
super.onDrawOver(c, parent, state);
return;
}
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; ++i) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int size = divider.getIntrinsicHeight();
final int top = (int) (child.getTop() - params.topMargin - size + child.getTranslationY());
final int bottom = top + size;
divider.setBounds(left, top, right, bottom);
divider.draw(c);
if (i == childCount - 1) {
final int newTop = (int) (child.getBottom() + params.bottomMargin + child.getTranslationY());
final int newBottom = newTop + size;
divider.setBounds(left, newTop, right, newBottom);
divider.draw(c);
}
}
}
private int getOrientation(RecyclerView parent) {
if (!(parent.getLayoutManager() instanceof LinearLayoutManager))
throw new IllegalStateException("Layout manager must be an instance of LinearLayoutManager");
return ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();
}
}
2) Ajoutez le décorateur à votre RecylerView:
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity()));
Nous pouvons décorer les articles en utilisant divers décorateurs attachés à la vue de recyclage tels que le DividerItemDecoration:
Utilisez simplement ce qui suit ... extrait de la réponse de EyesClear
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{Android.R.attr.listDivider};
private Drawable mDivider;
/**
* Default divider will be used
*/
public DividerItemDecoration(Context context) {
final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
mDivider = styledAttributes.getDrawable(0);
styledAttributes.recycle();
}
/**
* Custom divider will be used
*/
public DividerItemDecoration(Context context, int resId) {
mDivider = ContextCompat.getDrawable(context, resId);
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
} et ensuite utiliser ce qui précède comme suit
RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
recyclerView.addItemDecoration(itemDecoration);
Cela affichera des séparations entre chaque élément de la liste, comme indiqué ci-dessous:
Et pour ceux qui recherchent plus de détails, consultez ce guide tilisation de RecyclerView _ CodePath Android Cliffnotes
Certaines réponses suggèrent l'utilisation de marges, mais le problème est que: Si vous ajoutez les marges supérieure et inférieure, elles apparaîtront toutes les deux ajoutées entre les éléments et elles seront trop grandes. Si vous ne faites qu'ajouter l'un ou l'autre, il n'y aura pas de marge en haut ou en bas de la liste. Si vous ajoutez la moitié de la distance en haut et la moitié en bas, les marges extérieures seront trop petites.
Ainsi, la seule solution esthétiquement correcte est le diviseur que le système sait où appliquer correctement: entre les éléments mais pas au-dessus ou au-dessous des éléments.
S'il vous plaît laissez-moi savoir des doutes dans les commentaires ci-dessous :)
Ce lien a fonctionné comme un charme pour moi:
https://Gist.github.com/lapastillaroja/858caf1a82791b6c1a36
import Android.content.Context;
import Android.content.res.TypedArray;
import Android.graphics.Canvas;
import Android.graphics.Rect;
import Android.graphics.drawable.Drawable;
import Android.support.v7.widget.LinearLayoutManager;
import Android.support.v7.widget.RecyclerView;
import Android.util.AttributeSet;
import Android.view.View;
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
private boolean mShowFirstDivider = false;
private boolean mShowLastDivider = false;
public DividerItemDecoration(Context context, AttributeSet attrs) {
final TypedArray a = context
.obtainStyledAttributes(attrs, new int[]{Android.R.attr.listDivider});
mDivider = a.getDrawable(0);
a.recycle();
}
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
boolean showLastDivider) {
this(context, attrs);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
public DividerItemDecoration(Drawable divider) {
mDivider = divider;
}
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
boolean showLastDivider) {
this(divider);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (mDivider == null) {
return;
}
if (parent.getChildPosition(view) < 1) {
return;
}
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
outRect.top = mDivider.getIntrinsicHeight();
} else {
outRect.left = mDivider.getIntrinsicWidth();
}
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mDivider == null) {
super.onDrawOver(c, parent, state);
return;
}
// Initialization needed to avoid compiler warning
int left = 0, right = 0, top = 0, bottom = 0, size;
int orientation = getOrientation(parent);
int childCount = parent.getChildCount();
if (orientation == LinearLayoutManager.VERTICAL) {
size = mDivider.getIntrinsicHeight();
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
} else { //horizontal
size = mDivider.getIntrinsicWidth();
top = parent.getPaddingTop();
bottom = parent.getHeight() - parent.getPaddingBottom();
}
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) {
top = child.getTop() - params.topMargin;
bottom = top + size;
} else { //horizontal
left = child.getLeft() - params.leftMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
// show last divider
if (mShowLastDivider && childCount > 0) {
View child = parent.getChildAt(childCount - 1);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) {
top = child.getBottom() + params.bottomMargin;
bottom = top + size;
} else { // horizontal
left = child.getRight() + params.rightMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private int getOrientation(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getOrientation();
} else {
throw new IllegalStateException(
"DividerItemDecoration can only be used with a LinearLayoutManager.");
}
}
}
Puis dans votre activité:
mCategoryRecyclerView.addItemDecoration(
new DividerItemDecoration(this, null));
Ou ceci si vous utilisez un fragment:
mCategoryRecyclerView.addItemDecoration(
new DividerItemDecoration(getActivity(), null));
Tiré d'une recherche google, ajoutez ceci ItemDecoration à votre RecyclerView
:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
private boolean mShowFirstDivider = false;
private boolean mShowLastDivider = false;
public DividerItemDecoration(Context context, AttributeSet attrs) {
final TypedArray a = context
.obtainStyledAttributes(attrs, new int[]{Android.R.attr.listDivider});
mDivider = a.getDrawable(0);
a.recycle();
}
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
boolean showLastDivider) {
this(context, attrs);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
public DividerItemDecoration(Drawable divider) {
mDivider = divider;
}
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
boolean showLastDivider) {
this(divider);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (mDivider == null) {
return;
}
if (parent.getChildPosition(view) < 1) {
return;
}
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
outRect.top = mDivider.getIntrinsicHeight();
} else {
outRect.left = mDivider.getIntrinsicWidth();
}
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mDivider == null) {
super.onDrawOver(c, parent, state);
return;
}
// Initialization needed to avoid compiler warning
int left = 0, right = 0, top = 0, bottom = 0, size;
int orientation = getOrientation(parent);
int childCount = parent.getChildCount();
if (orientation == LinearLayoutManager.VERTICAL) {
size = mDivider.getIntrinsicHeight();
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
} else { //horizontal
size = mDivider.getIntrinsicWidth();
top = parent.getPaddingTop();
bottom = parent.getHeight() - parent.getPaddingBottom();
}
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) {
top = child.getTop() - params.topMargin;
bottom = top + size;
} else { //horizontal
left = child.getLeft() - params.leftMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
// show last divider
if (mShowLastDivider && childCount > 0) {
View child = parent.getChildAt(childCount - 1);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) {
top = child.getBottom() + params.bottomMargin;
bottom = top + size;
} else { // horizontal
left = child.getRight() + params.rightMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private int getOrientation(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getOrientation();
} else {
throw new IllegalStateException(
"DividerItemDecoration can only be used with a LinearLayoutManager.");
}
}
}
Au lieu de créer un shape xml
pour modifier la hauteur et la couleur du séparateur. Vous pouvez créer par programme comme
val divider = DividerItemDecoration(context,
DividerItemDecoration.VERTICAL)
divider.setDrawable(ShapeDrawable().apply {
intrinsicHeight = resources.getDimensionPixelOffset(R.dimen.dp_15)
Paint.color = Color.RED // note: currently (support version 28.0.0), we can not use tranparent color here, if we use transparent, we still see a small divider line. So if we want to display transparent space, we can set color = background color or we can create a custom ItemDecoration instead of DividerItemDecoration.
})
recycler_devices.addItemDecoration(divider)
Je pense qu'il est nécessaire de disposer d'une réponse simple, basée sur un code, qui n'utilise pas XML.
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL);
ShapeDrawable shapeDrawableForDivider = new ShapeDrawable(new RectShape());
int dividerThickness = // (int) (SomeOtherView.getHeight() * desiredPercent);
shapeDrawableForDivider.setIntrinsicHeight(dividerThickness);
shapeDrawableForDivider.setAlpha(0);
dividerItemDecoration.setDrawable(shapeDrawableForDivider);
recyclerView.addItemDecoration(dividerItemDecoration);
Trop tard mais pour GridLayoutManager
j'utilise ceci:
public class GridSpacesItemDecoration : RecyclerView.ItemDecoration
{
private int space;
public GridSpacesItemDecoration(int space) {
this.space = space;
}
public override void GetItemOffsets(Android.Graphics.Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
{
var position = parent.GetChildLayoutPosition(view);
/// Only for GridLayoutManager Layouts
var manager = parent.GetLayoutManager() as GridLayoutManager;
if (parent.GetChildLayoutPosition(view) < manager.SpanCount)
outRect.Top = space;
if (position % 2 != 0) {
outRect.Right = space;
}
outRect.Left = space;
outRect.Bottom = space;
}
}
Ce travail pour tout compte compte que vous avez.
Ollie.
J'ai ajouté une ligne dans la liste comme ci-dessous
<View
Android:id="@+id/divider"
Android:layout_width="match_parent"
Android:layout_height="1px"
Android:background="@color/dividerColor"/>
1px va tracer la ligne mince.
Si vous souhaitez masquer le séparateur pour la dernière ligne, saisissez
divider.setVisiblity(View.GONE);
sur onBindViewHolder pour le dernier élément de la liste.
Si vous souhaitez ajouter le même espace pour les éléments, le moyen le plus simple consiste à ajouter un remplissage supérieur + gauche pour RecycleView et des marges droite + inférieure aux éléments de la carte.
dimens.xml
<resources>
<dimen name="divider">1dp</dimen>
</resources>
list_item.xml
<CardView
Android:layout_marginBottom="@dimen/divider"
Android:layout_marginRight="@dimen/divider">
...
</CardView>
list.xml
<RecyclerView
Android:paddingLeft="@dimen/divider"
Android:paddingTop="@dimen/divider"
/>
Vous pouvez ajouter facilement par programmation.
Si votre gestionnaire de mise en page est Linearlayout, vous pouvez utiliser:
DividerItemDecoration est un RecyclerView.ItemDecoration qui peut être utilisé comme séparateur entre les éléments d'un LinearLayoutManager. Il prend en charge les orientations HORIZONTAL et VERTICAL.
mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
mLayoutManager.getOrientation());
recyclerView.addItemDecoration(mDividerItemDecoration);
public class CommonItemSpaceDecoration extends RecyclerView.ItemDecoration {
private int mSpace = 0;
private boolean mVerticalOrientation = true;
public CommonItemSpaceDecoration(int space) {
this.mSpace = space;
}
public CommonItemSpaceDecoration(int space, boolean verticalOrientation) {
this.mSpace = space;
this.mVerticalOrientation = verticalOrientation;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.top = SizeUtils.dp2px(view.getContext(), mSpace);
if (mVerticalOrientation) {
if (parent.getChildAdapterPosition(view) == 0) {
outRect.set(0, SizeUtils.dp2px(view.getContext(), mSpace), 0, SizeUtils.dp2px(view.getContext(), mSpace));
} else {
outRect.set(0, 0, 0, SizeUtils.dp2px(view.getContext(), mSpace));
}
} else {
if (parent.getChildAdapterPosition(view) == 0) {
outRect.set(SizeUtils.dp2px(view.getContext(), mSpace), 0, 0, 0);
} else {
outRect.set(SizeUtils.dp2px(view.getContext(), mSpace), 0, SizeUtils.dp2px(view.getContext(), mSpace), 0);
}
}
}
}
Cela ajoutera de l'espace en haut et en bas (ou à gauche et à droite) de chaque élément. Vous pourrez ensuite le définir sur votre recyclerView.
recyclerView.addItemDecoration(new CommonItemSpaceDecoration(16));
SizeUtils.Java
public class SizeUtils {
public static int dp2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
Une solution très simple consiste à utiliser RecyclerView-FlexibleDivider
Ajouter une dépendance:
compile 'com.yqritc:recyclerview-flexibledivider:1.4.0'
Ajoutez à votre liste de recyclage:
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(context).build());
Et tu as fini!
1.One of the Way est en utilisant cardview et recycler voir ensemble , nous pouvons facilement ajouter un effet de type diviseur. ex . https://developer.Android.com/training/material/lists-cards.html
2.et autre en ajoutant la vue en tant que diviseur à la liste list_item_layout de la vue recycleur .
<View
Android:id="@+id/view1"
Android:layout_width="match_parent"
Android:layout_height="1dp"
Android:background="@color/colorAccent" />
La RecyclerView
est un peu différente de la ListView
. En fait, la RecyclerView
a besoin d'une structure ListView
semblable à celle-ci. Par exemple, un LinearLayout
. La LinearLayout
a des paramètres pour diviser chaque élément. Dans le code ci-dessous, j'ai un RecyclerView
composé de CardView
objets dans un LinearLayout
avec un "remplissage" qui mettra un peu d'espace entre les éléments. Faites de cet espace vraiment petit et vous obtenez une ligne.
Voici la vue Recycler dans recyclerview_layout.xml
<RelativeLayout 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: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=".ToDoList">
<!-- A RecyclerView with some commonly used attributes -->
<Android.support.v7.widget.RecyclerView
Android:id="@+id/todo_recycler_view"
Android:scrollbars="vertical"
Android:layout_width="match_parent"
Android:layout_height="match_parent"/>
</RelativeLayout>
Et voici à quoi chaque élément ressemble (et il apparaît divisé en raison d'Android: le remplissage dans le LinearLayout qui entoure tout.) Dans un autre fichier: cards_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:orientation="vertical" Android:layout_width="match_parent"
Android:layout_height="match_parent"
**Android:padding="@dimen/activity_vertical_margin"**>
<!-- A CardView that contains a TextView -->
<Android.support.v7.widget.CardView
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="100dp"
Android:elevation="30dp"
card_view:cardElevation="3dp">
<TextView
Android:id="@+id/info_text"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
/>
</Android.support.v7.widget.CardView>
</LinearLayout>
Implémenter sa propre version de RecyclerView.ItemDecoration
public class SpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spacingPx;
private boolean addStartSpacing;
private boolean addEndSpacing;
public SpacingItemDecoration(int spacingPx) {
this(spacingPx, false, false);
}
public SpacingItemDecoration(int spacingPx, boolean addStartSpacing, boolean addEndSpacing) {
this.spacingPx = spacingPx;
this.addStartSpacing = addStartSpacing;
this.addEndSpacing = addEndSpacing;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (spacingPx <= 0) {
return;
}
if (addStartSpacing && parent.getChildLayoutPosition(view) < 1 || parent.getChildLayoutPosition(view) >= 1) {
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
outRect.top = spacingPx;
} else {
outRect.left = spacingPx;
}
}
if (addEndSpacing && parent.getChildAdapterPosition(view) == getTotalItemCount(parent) - 1) {
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
outRect.bottom = spacingPx;
} else {
outRect.right = spacingPx;
}
}
}
private int getTotalItemCount(RecyclerView parent) {
return parent.getAdapter().getItemCount();
}
private int getOrientation(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
return ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();
} else {
throw new IllegalStateException("SpacingItemDecoration can only be used with a LinearLayoutManager.");
}
}
}
PrimeAdapter
En utilisant PrimeAdapter , la gestion des séparateurs dans RecyclerView
s pourrait être si simple. Il offre de multiples fonctionnalités et plus de flexibilité pour créer et gérer des séparateurs.
Vous pouvez créer un adaptateur comme suit: (Voir la documentation complète sur l’utilisation dans github )
val adapter = PrimeAdapter.with(recyclerView)
.setLayoutManager(LinearLayoutManager(activity))
.set()
.build(ActorAdapter::class.Java)
Après avoir créé une instance d'adaptateur, vous pouvez simplement ajouter un diviseur simplement en utilisant:
//----- default divider:
adapter.setDivider()
//----- divider with custom drawable:
adapter.setDivider(ContextCompat.getDrawable(context, R.drawable.divider))
//----- divider with custom color:
adapter.setDivider(Color.RED)
//----- divider with custom color and custom inset:
adapter.setDivider(Color.RED, insetLeft = 16, insetRight = 16)
//----- deactivate dividers:
adapter.setDivider(null)
Utilisez cette classe pour définir le séparateur dans votre RecyclerView
.
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
private boolean includeEdge;
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item position
int column = position % spanCount; // item column
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)
if (position < spanCount) { // top Edge
outRect.top = spacing;
}
outRect.bottom = spacing; // item bottom
} else {
outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
if (position >= spanCount) {
outRect.top = spacing; // item top
}
}
}
}
public class VerticalItemDecoration extends RecyclerView.ItemDecoration {
private boolean verticalOrientation = true;
private int space = 10;
public VerticalItemDecoration(int value, boolean verticalOrientation) {
this.space = value;
this.verticalOrientation = verticalOrientation;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
//skip first item in the list
if (parent.getChildAdapterPosition(view) != 0) {
if (verticalOrientation) {
outRect.set(space, 0, 0, 0);
} else if (!verticalOrientation) {
outRect.set(0, space, 0, 0);
}
}
}
}
mCompletedShippingRecyclerView.addItemDecoration(new VerticalItemDecoration(20,false));
J'ai un moyen très simple d'ajouter un diviseur dans RecyclerView. Utilisez un adaptateur personnalisé pour modifier la disposition de la vue recycleur, puis ajoutez aux éléments de la vue recycleur LinearLayout avec une couleur d'arrière-plan (qui sera la couleur du séparateur) et ajoutez une hauteur de 1dp (ou selon vos besoins) et une largeur identique à celle du parent. .
Voici un exemple de code.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:orientation="vertical" Android:layout_width="match_parent"
Android:layout_height="match_parent">
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:orientation="horizontal"
Android:padding="18dp">
<TextView
Android:id="@+id/list_row_SNO"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_weight=".8"
Android:layout_gravity="end"
Android:text="44."
Android:textAlignment="center"
Android:textSize="24sp"
Android:textColor="@color/colorBlack"
Android:fontFamily="sans-serif-condensed" />
<TextView
Android:id="@+id/list_row_Heading"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_weight=".2"
Android:layout_gravity="start"
Android:text="Student's application for leave and this what"
Android:textAlignment="textStart"
Android:textSize="24sp"
Android:textColor="@color/colorBlack"
Android:fontFamily="sans-serif-condensed" />
</LinearLayout>
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="1dp"
Android:background="@color/colorHighlight">
</LinearLayout>
RecyclerView ne fournit pas une interface simple pour dessiner des séparateurs de listes. Mais en réalité, cela nous fournit un moyen beaucoup plus flexible d’établir des séparateurs. Nous utilisons RecyclerView.ItemDecoration pour décorer les carreaux de RecyclerView avec des diviseurs ou tout autre matériau de votre choix. C'est aussi pourquoi il s'appelle ItemDecoration.
Comme décrit dans Lignes directrices sur la conception du métal :
Le diviseur se situe dans la ligne de base de la tuile.
Ainsi, si vous souhaitez suivre les directives de conception de matériel, vous n'avez pas besoin d'espace supplémentaire pour dessiner les séparateurs. Il suffit de les dessiner sur les carreaux. Cependant, vous avez le droit de faire ce que vous voulez faire. J'ai donc mis en place un système qui vous permet de définir des incrustations et de dessiner sur/sous les carreaux.
public class InsetDivider extends RecyclerView.ItemDecoration {
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Paint mPaint;
// in pixel
private int mDividerHeight;
// left inset for vertical list, top inset for horizontal list
private int mFirstInset;
// right inset for vertical list, bottom inset for horizontal list
private int mSecondInset;
private int mColor;
private int mOrientation;
// set it to true to draw divider on the tile, or false to draw beside the tile.
// if you set it to false and have inset at the same time, you may see the background of
// the parent of RecyclerView.
private boolean mOverlay;
private InsetDivider() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.FILL);
}
public int getDividerHeight() {
return mDividerHeight;
}
public void setDividerHeight(int dividerHeight) {
this.mDividerHeight = dividerHeight;
}
public int getFirstInset() {
return mFirstInset;
}
public void setFirstInset(int firstInset) {
this.mFirstInset = firstInset;
}
public int getSecondInset() {
return mSecondInset;
}
public void setSecondInset(int secondInset) {
this.mSecondInset = secondInset;
}
public int getColor() {
return mColor;
}
public void setColor(int color) {
this.mColor = color;
mPaint.setColor(color);
}
public int getOrientation() {
return mOrientation;
}
public void setOrientation(int orientation) {
this.mOrientation = orientation;
}
public boolean getOverlay() {
return mOverlay;
}
public void setOverlay(boolean overlay) {
this.mOverlay = overlay;
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
protected void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft() + mFirstInset;
final int right = parent.getWidth() - parent.getPaddingRight() - mSecondInset;
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
if (parent.getChildAdapterPosition(child) == (parent.getAdapter().getItemCount() - 1)) {
continue;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int bottom;
final int top;
if (mOverlay) {
bottom = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));
top = bottom - mDividerHeight;
} else {
top = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));
bottom = top + mDividerHeight;
}
c.drawRect(left, top, right, bottom, mPaint);
}
}
protected void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop() + mFirstInset;
final int bottom = parent.getHeight() - parent.getPaddingBottom() - mSecondInset;
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
if (parent.getChildAdapterPosition(child) == (parent.getAdapter().getItemCount() - 1)) {
continue;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int right;
final int left;
if (mOverlay) {
right = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));
left = right - mDividerHeight;
} else {
left = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));
right = left + mDividerHeight;
}
c.drawRect(left, top, right, bottom, mPaint);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (mOverlay) {
super.getItemOffsets(outRect, view, parent, state);
return;
}
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDividerHeight);
} else {
outRect.set(0, 0, mDividerHeight, 0);
}
}
/**
* Handy builder for creating {@link InsetDivider} instance.
*/
public static class Builder {
private Context mContext;
private int mDividerHeight;
private int mFirstInset;
private int mSecondInset;
private int mColor;
private int mOrientation;
private boolean mOverlay = true; // set default to true to follow Material Design Guidelines
public Builder(Context context) {
mContext = context;
}
public Builder dividerHeight(int dividerHeight) {
mDividerHeight = dividerHeight;
return this;
}
public Builder insets(int firstInset, int secondInset) {
mFirstInset = firstInset;
mSecondInset = secondInset;
return this;
}
public Builder color(@ColorInt int color) {
mColor = color;
return this;
}
public Builder orientation(int orientation) {
mOrientation = orientation;
return this;
}
public Builder overlay(boolean overlay) {
mOverlay = overlay;
return this;
}
public InsetDivider build() {
InsetDivider insetDivider = new InsetDivider();
if (mDividerHeight == 0) {
// Set default divider height to 1dp.
insetDivider.setDividerHeight(mContext.getResources().getDimensionPixelSize(R.dimen.divider_height));
} else if (mDividerHeight > 0) {
insetDivider.setDividerHeight(mDividerHeight);
} else {
throw new IllegalArgumentException("Divider's height can't be negative.");
}
insetDivider.setFirstInset(mFirstInset < 0 ? 0 : mFirstInset);
insetDivider.setSecondInset(mSecondInset < 0 ? 0 : mSecondInset);
if (mColor == 0) {
throw new IllegalArgumentException("Don't forget to set color");
} else {
insetDivider.setColor(mColor);
}
if (mOrientation != InsetDivider.HORIZONTAL_LIST && mOrientation != InsetDivider.VERTICAL_LIST) {
throw new IllegalArgumentException("Invalid orientation");
} else {
insetDivider.setOrientation(mOrientation);
}
insetDivider.setOverlay(mOverlay);
return insetDivider;
}
}
}
Et vous pouvez l'utiliser comme ceci:
ItemDecoration divider = new InsetDivider.Builder(this)
.orientation(InsetDivider.VERTICAL_LIST)
.dividerHeight(getResources().getDimensionPixelSize(R.dimen.divider_height))
.color(getResources().getColor(R.color.colorAccent))
.insets(getResources().getDimensionPixelSize(R.dimen.divider_inset), 0)
.overlay(true)
.build();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addItemDecoration(divider);
J'ai également écrit une application de démonstration sur la manière de mettre en œuvre ItemDecoration et de les utiliser. Vous pouvez consulter mon dépôt GitHub Dividers-For-RecyclerView . Il comporte trois implémentations:
Voici mon approche paresseuse mais cela fonctionne: enveloppez le CardView dans une mise en page et définissez un remplissage/marge sur la mise en page parent pour imiter le séparateur, et forcez le diviseur normal à null
list_item.xml
<LinearLayout
Android:id="@+id/entry_item_layout_container"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:orientation="vertical"
Android:paddingBottom="<divider_size>" > // this is the divider
<CardView
Android:layout_width="<width_size>"
Android:layout_height="<height_size>">
...
</CardView>
</LinearLayout
list.xml
<RecyclerView
Android:divider="@null"
Android:layout_width="<width_size>"
Android:layout_height="<height_size>"
...
/>