Vous pouvez ajouter un indicateur à l'aide de RecyclerView.ItemDecoration.
Dessinez simplement quelques lignes ou cercles en bas et utilisez layoutManager.findFirstVisibleItemPosition()
pour obtenir l'élément actif actuel. Étant donné que les téléavertisseurs ont tendance à remplir toute la largeur, il s'agit d'un moyen efficace d'obtenir l'élément affiché. Cela nous permet également de calculer la distance de défilement en comparant le bord gauche de l'enfant aux parents.
Vous trouverez ci-dessous un exemple de décoration qui dessine des lignes et anime entre elles
public class LinePagerIndicatorDecoration extends RecyclerView.ItemDecoration {
private int colorActive = 0xFFFFFFFF;
private int colorInactive = 0x66FFFFFF;
private static final float DP = Resources.getSystem().getDisplayMetrics().density;
/**
* Height of the space the indicator takes up at the bottom of the view.
*/
private final int mIndicatorHeight = (int) (DP * 16);
/**
* Indicator stroke width.
*/
private final float mIndicatorStrokeWidth = DP * 2;
/**
* Indicator width.
*/
private final float mIndicatorItemLength = DP * 16;
/**
* Padding between indicators.
*/
private final float mIndicatorItemPadding = DP * 4;
/**
* Some more natural animation interpolation
*/
private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
private final Paint mPaint = new Paint();
public LinePagerIndicatorDecoration() {
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(mIndicatorStrokeWidth);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
int itemCount = parent.getAdapter().getItemCount();
// center horizontally, calculate width and subtract half from center
float totalLength = mIndicatorItemLength * itemCount;
float paddingBetweenItems = Math.max(0, itemCount - 1) * mIndicatorItemPadding;
float indicatorTotalWidth = totalLength + paddingBetweenItems;
float indicatorStartX = (parent.getWidth() - indicatorTotalWidth) / 2F;
// center vertically in the allotted space
float indicatorPosY = parent.getHeight() - mIndicatorHeight / 2F;
drawInactiveIndicators(c, indicatorStartX, indicatorPosY, itemCount);
// find active page (which should be highlighted)
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
int activePosition = layoutManager.findFirstVisibleItemPosition();
if (activePosition == RecyclerView.NO_POSITION) {
return;
}
// find offset of active page (if the user is scrolling)
final View activeChild = layoutManager.findViewByPosition(activePosition);
int left = activeChild.getLeft();
int width = activeChild.getWidth();
// on swipe the active item will be positioned from [-width, 0]
// interpolate offset for smooth animation
float progress = mInterpolator.getInterpolation(left * -1 / (float) width);
drawHighlights(c, indicatorStartX, indicatorPosY, activePosition, progress, itemCount);
}
private void drawInactiveIndicators(Canvas c, float indicatorStartX, float indicatorPosY, int itemCount) {
mPaint.setColor(colorInactive);
// width of item indicator including padding
final float itemWidth = mIndicatorItemLength + mIndicatorItemPadding;
float start = indicatorStartX;
for (int i = 0; i < itemCount; i++) {
// draw the line for every item
c.drawLine(start, indicatorPosY, start + mIndicatorItemLength, indicatorPosY, mPaint);
start += itemWidth;
}
}
private void drawHighlights(Canvas c, float indicatorStartX, float indicatorPosY,
int highlightPosition, float progress, int itemCount) {
mPaint.setColor(colorActive);
// width of item indicator including padding
final float itemWidth = mIndicatorItemLength + mIndicatorItemPadding;
if (progress == 0F) {
// no swipe, draw a normal indicator
float highlightStart = indicatorStartX + itemWidth * highlightPosition;
c.drawLine(highlightStart, indicatorPosY,
highlightStart + mIndicatorItemLength, indicatorPosY, mPaint);
} else {
float highlightStart = indicatorStartX + itemWidth * highlightPosition;
// calculate partial highlight
float partialLength = mIndicatorItemLength * progress;
// draw the cut off highlight
c.drawLine(highlightStart + partialLength, indicatorPosY,
highlightStart + mIndicatorItemLength, indicatorPosY, mPaint);
// draw the highlight overlapping to the next item as well
if (highlightPosition < itemCount - 1) {
highlightStart += itemWidth;
c.drawLine(highlightStart, indicatorPosY,
highlightStart + partialLength, indicatorPosY, mPaint);
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.bottom = mIndicatorHeight;
}
}
Ce qui vous donnera un résultat comme le suivant
Il y a aussi un article de blog qui explique plus en détail le fonctionnement de la décoration ici et le code source complet est disponible sur GitHub
J'ai changé le code des cercles. Suppression du code pour dessiner une ligne et le même est remplacé par des méthodes de dessin en cercle. Veuillez trouver ci-dessous la classe complète:
public class CirclePagerIndicatorDecoration extends RecyclerView.ItemDecoration {
private int colorActive = 0xDE000000;
private int colorInactive = 0x33000000;
private static final float DP = Resources.getSystem().getDisplayMetrics().density;
/**
* Height of the space the indicator takes up at the bottom of the view.
*/
private final int mIndicatorHeight = (int) (DP * 16);
/**
* Indicator stroke width.
*/
private final float mIndicatorStrokeWidth = DP * 4;
/**
* Indicator width.
*/
private final float mIndicatorItemLength = DP * 4;
/**
* Padding between indicators.
*/
private final float mIndicatorItemPadding = DP * 8;
/**
* Some more natural animation interpolation
*/
private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
private final Paint mPaint = new Paint();
public CirclePagerIndicatorDecoration() {
mPaint.setStrokeWidth(mIndicatorStrokeWidth);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
int itemCount = parent.getAdapter().getItemCount();
// center horizontally, calculate width and subtract half from center
float totalLength = mIndicatorItemLength * itemCount;
float paddingBetweenItems = Math.max(0, itemCount - 1) * mIndicatorItemPadding;
float indicatorTotalWidth = totalLength + paddingBetweenItems;
float indicatorStartX = (parent.getWidth() - indicatorTotalWidth) / 2F;
// center vertically in the allotted space
float indicatorPosY = parent.getHeight() - mIndicatorHeight / 2F;
drawInactiveIndicators(c, indicatorStartX, indicatorPosY, itemCount);
// find active page (which should be highlighted)
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
int activePosition = layoutManager.findFirstVisibleItemPosition();
if (activePosition == RecyclerView.NO_POSITION) {
return;
}
// find offset of active page (if the user is scrolling)
final View activeChild = layoutManager.findViewByPosition(activePosition);
int left = activeChild.getLeft();
int width = activeChild.getWidth();
int right = activeChild.getRight();
// on swipe the active item will be positioned from [-width, 0]
// interpolate offset for smooth animation
float progress = mInterpolator.getInterpolation(left * -1 / (float) width);
drawHighlights(c, indicatorStartX, indicatorPosY, activePosition, progress);
}
private void drawInactiveIndicators(Canvas c, float indicatorStartX, float indicatorPosY, int itemCount) {
mPaint.setColor(colorInactive);
// width of item indicator including padding
final float itemWidth = mIndicatorItemLength + mIndicatorItemPadding;
float start = indicatorStartX;
for (int i = 0; i < itemCount; i++) {
c.drawCircle(start, indicatorPosY, mIndicatorItemLength / 2F, mPaint);
start += itemWidth;
}
}
private void drawHighlights(Canvas c, float indicatorStartX, float indicatorPosY,
int highlightPosition, float progress) {
mPaint.setColor(colorActive);
// width of item indicator including padding
final float itemWidth = mIndicatorItemLength + mIndicatorItemPadding;
if (progress == 0F) {
// no swipe, draw a normal indicator
float highlightStart = indicatorStartX + itemWidth * highlightPosition;
c.drawCircle(highlightStart, indicatorPosY, mIndicatorItemLength / 2F, mPaint);
} else {
float highlightStart = indicatorStartX + itemWidth * highlightPosition;
// calculate partial highlight
float partialLength = mIndicatorItemLength * progress + mIndicatorItemPadding*progress;
c.drawCircle(highlightStart + partialLength, indicatorPosY, mIndicatorItemLength / 2F, mPaint);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.bottom = mIndicatorHeight;
}
}
Merci beaucoup, LB Gupta Happy Coding !!!!!
J'ai copié la même réponse qui est donnée par David Medenjak, mais pour faire les cercles en dessous de la vue de recyclage. J'ai mis à jour quelques lignes de code dans la réponse ci-dessus, veuillez les consulter et les utiliser en conséquence.
/**
* Created by shobhan on 4/10/17.
*/
public class CirclePagerIndicatorDecoration extends RecyclerView.ItemDecoration {
private int colorActive = 0x727272;
private int colorInactive = 0xF44336;
private static final float DP = Resources.getSystem().getDisplayMetrics().density;
/**
* Height of the space the indicator takes up at the bottom of the view.
*/
private final int mIndicatorHeight = (int) (DP * 16);
/**
* Indicator stroke width.
*/
private final float mIndicatorStrokeWidth = DP * 2;
/**
* Indicator width.
*/
private final float mIndicatorItemLength = DP * 16;
/**
* Padding between indicators.
*/
private final float mIndicatorItemPadding = DP * 4;
/**
* Some more natural animation interpolation
*/
private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
private final Paint mPaint = new Paint();
public CirclePagerIndicatorDecoration() {
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(mIndicatorStrokeWidth);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
int itemCount = parent.getAdapter().getItemCount();
// center horizontally, calculate width and subtract half from center
float totalLength = mIndicatorItemLength * itemCount;
float paddingBetweenItems = Math.max(0, itemCount - 1) * mIndicatorItemPadding;
float indicatorTotalWidth = totalLength + paddingBetweenItems;
float indicatorStartX = (parent.getWidth() - indicatorTotalWidth) / 2F;
// center vertically in the allotted space
float indicatorPosY = parent.getHeight() - mIndicatorHeight / 2F;
drawInactiveIndicators(c, indicatorStartX, indicatorPosY, itemCount);
// find active page (which should be highlighted)
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
int activePosition = layoutManager.findFirstVisibleItemPosition();
if (activePosition == RecyclerView.NO_POSITION) {
return;
}
// find offset of active page (if the user is scrolling)
final View activeChild = layoutManager.findViewByPosition(activePosition);
int left = activeChild.getLeft();
int width = activeChild.getWidth();
// on swipe the active item will be positioned from [-width, 0]
// interpolate offset for smooth animation
float progress = mInterpolator.getInterpolation(left * -1 / (float) width);
drawHighlights(c, indicatorStartX, indicatorPosY, activePosition, progress, itemCount);
}
private void drawInactiveIndicators(Canvas c, float indicatorStartX, float indicatorPosY, int itemCount) {
mPaint.setColor(Color.GRAY);
// width of item indicator including padding
final float itemWidth = mIndicatorItemLength + mIndicatorItemPadding;
float start = indicatorStartX;
for (int i = 0; i < itemCount; i++) {
// draw the line for every item
c.drawCircle(start + mIndicatorItemLength,indicatorPosY,itemWidth/6,mPaint);
// c.drawLine(start, indicatorPosY, start + mIndicatorItemLength, indicatorPosY, mPaint);
start += itemWidth;
}
}
private void drawHighlights(Canvas c, float indicatorStartX, float indicatorPosY,
int highlightPosition, float progress, int itemCount) {
mPaint.setColor(Color.RED);
// width of item indicator including padding
final float itemWidth = mIndicatorItemLength + mIndicatorItemPadding;
if (progress == 0F) {
// no swipe, draw a normal indicator
float highlightStart = indicatorStartX + itemWidth * highlightPosition;
/* c.drawLine(highlightStart, indicatorPosY,
highlightStart + mIndicatorItemLength, indicatorPosY, mPaint);
*/
c.drawCircle(highlightStart,indicatorPosY,itemWidth/6,mPaint);
} else {
float highlightStart = indicatorStartX + itemWidth * highlightPosition;
// calculate partial highlight
float partialLength = mIndicatorItemLength * progress;
c.drawCircle(highlightStart + mIndicatorItemLength,indicatorPosY,itemWidth/6,mPaint);
// draw the cut off highlight
/* c.drawLine(highlightStart + partialLength, indicatorPosY,
highlightStart + mIndicatorItemLength, indicatorPosY, mPaint);
*/
// draw the highlight overlapping to the next item as well
/* if (highlightPosition < itemCount - 1) {
highlightStart += itemWidth;
*//*c.drawLine(highlightStart, indicatorPosY,
highlightStart + partialLength, indicatorPosY, mPaint);*//*
c.drawCircle(highlightStart ,indicatorPosY,itemWidth/4,mPaint);
}*/
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.bottom = mIndicatorHeight;
}
}
Et appliquez-le à la vue de recyclage comme suit
//for horizontal scroll for recycler view
LinearLayoutManager linearLayoutManager
= new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
recyclerview.setLayoutManager(linearLayoutManager);
recyclerview.addItemDecoration(new CirclePagerIndicatorDecoration());
en cas de besoin, j'ai écrit ma propre bibliothèque pour cela (après beaucoup de recherches): indicateur RecyclerView . Voici comment procéder:
<com.kingfisher.easyviewindicator.RecyclerViewIndicator
Android:id="@+id/circleIndicator"
Android:layout_width="match_parent"
Android:layout_height="20dp"
app:avi_animation_enable="true"
app:avi_drawable="@drawable/blue_radius"
app:avi_drawable_unselected="@drawable/gray_radius"
app:avi_height="10dp"
app:avi_margin="10dp"
app:avi_width="10dp"
app:layout_constraintTop_toBottomOf="@+id/recyclerView">
</com.kingfisher.easyviewindicator.RecyclerViewIndicator>
// In code:
recyclerView.setAdapter(new TestAdapter());
recyclerViewIndicator.setRecyclerView(recyclerView);