J'ai un assez simple RecyclerView. Voici comment je règle le diviseur
DividerItemDecoration itemDecorator = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
itemDecorator.setDrawable(ContextCompat.getDrawable(getActivity(), R.drawable.news_divider));
recyclerView.addItemDecoration(itemDecorator);
Et ceci est drawable/news_divider.xml
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android" Android:shape="rectangle">
<solid Android:color="@color/white_two"/>
<size Android:height="1dp"/>
</shape>
Le problème est que, pour une raison stupide, le séparateur n’est pas simplement créé entre les éléments. Mais aussi après le dernier article. Et je le veux seulement entre les articles pas après chaque article.
Avez-vous une idée de comment empêcher le séparateur de s'afficher après le dernier élément?
A bientôt et merci
Essayez ce code, il ne montrera pas de diviseur pour le dernier article.
public class DividerItemDecorator extends RecyclerView.ItemDecoration {
private Drawable mDivider;
public DividerItemDecorator(Drawable divider) {
mDivider = divider;
}
@Override
public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
int dividerLeft = parent.getPaddingLeft();
int dividerRight = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i <= childCount - 2; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int dividerTop = child.getBottom() + params.bottomMargin;
int dividerBottom = dividerTop + mDivider.getIntrinsicHeight();
mDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
mDivider.draw(canvas);
}
}
}
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="@color/grey_300" />
</shape>
Définissez votre Divider comme ceci:
RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(ContextCompat.getDrawable(context, R.drawable.divider));
recyclerView.addItemDecoration(dividerItemDecoration);
Comme proposé ici vous pouvez étendre DividerItemDecoration comme ceci:
recyclerView.addItemDecoration(
new DividerItemDecoration(context, linearLayoutManager.getOrientation()) {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
// hide the divider for the last child
if (position == parent.getAdapter().getItemCount() - 1) {
outRect.setEmpty();
} else {
super.getItemOffsets(outRect, view, parent, state);
}
}
}
);
[UPDATE]
@ Rebecca Hsieh a souligné:
Ceci fonctionne lorsque votre vue d'élément dans RecyclerView n'a pas d'arrière-plan transparent, par exemple,
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:orientation="horizontal"
Android:background="#ffffff">
...
</LinearLayout>
DividerItemDecoration.getItemOffsets est appelé par RecyclerView pour mesurer la position de l'enfant. Cette solution mettra le dernier séparateur derrière le dernier élément. Par conséquent, la vue de l'élément dans RecyclerView doit avoir un arrière-plan pour couvrir le dernier séparateur, ce qui donne l'impression qu'il est masqué.
Autre solution
Si vous n'aimez pas que le séparateur soit dessiné derrière, vous pouvez simplement copier ou étendre la classe DividerItemDecoration et changer son comportement d'affichage en modifiant for (int i = 0; i < childCount; i++)
en for (int i = 0; i < childCount - 1; i++)
La réponse acceptée n'alloue pas d'espace pour la décoration car elle ne remplace pas getItemOffsets()
J'ai modifié le DividerItemDecoration à partir de la bibliothèque de support pour exclure la décoration du dernier élément
public class DividerItemDecorator extends RecyclerView.ItemDecoration {
private Drawable mDivider;
private final Rect mBounds = new Rect();
public DividerItemDecorator(Drawable divider) {
mDivider = divider;
}
@Override
public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
canvas.save();
final int left;
final int right;
if (parent.getClipToPadding()) {
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
canvas.clipRect(left, parent.getPaddingTop(), right,
parent.getHeight() - parent.getPaddingBottom());
} else {
left = 0;
right = parent.getWidth();
}
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount - 1; i++) {
final View child = parent.getChildAt(i);
parent.getDecoratedBoundsWithMargins(child, mBounds);
final int bottom = mBounds.bottom + Math.round(child.getTranslationY());
final int top = bottom - mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
canvas.restore();
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) == state.getItemCount() - 1) {
outRect.setEmpty();
} else
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
}
}
Pour appliquer le décorateur, utilisez
RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(dividerDrawable);
recyclerView.addItemDecoration(dividerItemDecoration);
La source d'inclusion d'orientation peut être trouvée ici https://Gist.github.com/abdulalin/146f8ca42aa8322692b15663b8d508ff
Créez votre propre classe de diviseur ( Exemple ici )
Dans le code qui dessine le séparateur, vérifiez d’abord si vous dessinez le séparateur du dernier élément de la liste. Si c'est le cas, ne le dessinez pas.
Sachez simplement que si vous remplacez OnDrawOver
, il affichera en haut de votre vue les barres de défilement, etc. Il vaut mieux s'en tenir à OnDraw
. Beaucoup d'exemples sur Google mais this est un bon tutoriel sur la création de vos propres décorateurs.
Voici la classe DividerDecorator
que j'utilise dans mes applications et qui supprime la dernière ligne du dernier élément.
public class DividerDecorator extends RecyclerView.ItemDecoration {
private Drawable mDivider;
public DividerDecorator(Context context) {
mDivider = context.getResources().getDrawable(R.drawable.recyclerview_divider);
}
@Override
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);
}
}
}
Vous pouvez le définir sur votre RecyclerView
avec le code suivant:
mRecyclerViewEvent.addItemDecoration(new DividerDecorator(context));
Voici le recyclerview_divider.xml
<size
Android:width="1dp"
Android:height="1dp" />
<solid Android:color="@color/DividerColor" />
Ceci est une version personnalisée de Android support DividerItemDecoration
qui ignore le dernier élément:
https://Gist.github.com/mohsenoid/8ffdfa53f0465533833b0b44257aa641
la principale différence est:
private fun drawVertical(canvas: Canvas, parent: RecyclerView) {
canvas.save()
val left: Int
val right: Int
if (parent.clipToPadding) {
left = parent.paddingLeft
right = parent.width - parent.paddingRight
canvas.clipRect(left, parent.paddingTop, right,
parent.height - parent.paddingBottom)
} else {
left = 0
right = parent.width
}
val childCount = parent.childCount
for (i in 0 until childCount - 1) {
val child = parent.getChildAt(i)
parent.getDecoratedBoundsWithMargins(child, mBounds)
val bottom = mBounds.bottom + Math.round(child.translationY)
val top = bottom - mDivider!!.intrinsicHeight
mDivider!!.setBounds(left, top, right, bottom)
mDivider!!.draw(canvas)
}
canvas.restore()
}
private fun drawHorizontal(canvas: Canvas, parent: RecyclerView) {
canvas.save()
val top: Int
val bottom: Int
if (parent.clipToPadding) {
top = parent.paddingTop
bottom = parent.height - parent.paddingBottom
canvas.clipRect(parent.paddingLeft, top,
parent.width - parent.paddingRight, bottom)
} else {
top = 0
bottom = parent.height
}
val childCount = parent.childCount
for (i in 0 until childCount - 1) {
val child = parent.getChildAt(i)
parent.layoutManager.getDecoratedBoundsWithMargins(child, mBounds)
val right = mBounds.right + Math.round(child.translationX)
val left = right - mDivider!!.intrinsicWidth
mDivider!!.setBounds(left, top, right, bottom)
mDivider!!.draw(canvas)
}
canvas.restore()
}