答案 0 :(得分:27)
您可以使用RecyclerView.ItemDecoration添加指标。
只需在底部绘制一些线条或圆圈,然后使用class OptionButton extends Component {
constructor(props) {
super(props)
this.state = {
selected: false
}
}
unselectSet() {
this.setState({
selected: false
})
}
selectSet() {
this.setState({
selected: true
})
}
toggler() {
this.state.selected ? this.unselectSet() : this.selectSet()
}
render() {
return (
<div>
<button onClick={() => this.toggler()} style={numberButtonStyle}>{this.props.opt}</button>
</div>
)
}
}
获取当前有效项目。由于寻呼机倾向于填充整个宽度,因此这是获取显示项目的累积方式。这也允许我们通过比较孩子的左边缘和父母来计算滚动距离。
下面是一个样本装饰,它在它们之间绘制一些线条和动画
layoutManager.findFirstVisibleItemPosition()
这将为您提供如下结果
还有一篇博文更详细地介绍了装饰的工作原理here,完整的源代码是available at GitHub
答案 1 :(得分:18)
我更改了圈子的代码。删除了绘制线的代码,并将其替换为绘制圆方法。 请在下面找到完整的课程:
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;
}
}
非常感谢, LB古普塔 快乐编码!!!!!
答案 2 :(得分:4)
我复制了David Medenjak给出的相同答案,但是要将圈子放在recyclerview下面。我在上面的答案中更新了几行代码,请查看并使用相应的内容。
/**
* 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;
}
}
并将其应用于recyclerview,如下所示
//for horizontal scroll for recycler view
LinearLayoutManager linearLayoutManager
= new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
recyclerview.setLayoutManager(linearLayoutManager);
recyclerview.addItemDecoration(new CirclePagerIndicatorDecoration());
答案 3 :(得分:4)
如果有人需要,我为此编写了自己的库(经过大量搜索):RecyclerView indicator。这是你如何做到的:
<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);
答案 4 :(得分:1)
您可以在Recycler视图小部件下将PageIndicator.java类添加到.xml中
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/color_white">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_notice_board_cards"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen_16dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_high_lights" />
<com.abc.widget.PageIndicator
android:id="@+id/ll_image_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:layout_marginStart="@dimen/dimen_16dp"
android:layout_marginTop="@dimen/dimen_12dp"
android:layout_marginEnd="@dimen/dimen_16dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/tv_cards_count"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rv_notice_board_cards"
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
PageIndicator.java类如下
public class PageIndicator extends LinearLayout {
private ImageView[] imageIndications;
public PageIndicator(Context context) {
super(context);
}
public PageIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* method to create the pageIndicator
*/
public void createPageIndicator(int pageCount, int focusedPageDrawable,
int unFocusedPageDrawable) {
imageIndications = new ImageView[pageCount];
ImageView indicatorImageView;
for (int i = 0; i < pageCount; i++) {
indicatorImageView = new ImageView(getContext());
int size = BaseUtils.INSTANCE.getDensityPixelValue(getContext(), 8);
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(size, size);
params.setMargins(8, 0, 4, 0);
indicatorImageView.setLayoutParams(params);
// method to change the page icon
changePageIcon(i, 0, indicatorImageView, focusedPageDrawable, unFocusedPageDrawable);
imageIndications[i] = indicatorImageView;
this.addView(indicatorImageView);
}
}
/**
* method to handle the PageChangeListener for ViewPager
*
* @param size the total number of images available for product
* @param position the current position of ViewPager
* @param focusedPageDrawable
* @param unFocusedPageDrawable
*/
public void handleViewPagerScroll(int size, int position, int focusedPageDrawable,
int unFocusedPageDrawable) {
for (int i = 0; i < size && i < imageIndications.length; i++) {
changePageIcon(position, i, imageIndications[i], focusedPageDrawable, unFocusedPageDrawable);
imageIndications[i].getLayoutParams().width = imageIndications[i].getDrawable().getIntrinsicWidth();
}
}
/**
* method to change the page icon
*
* @param position
* @param indicatorImageView
* @param focusedPageDrawable
* @param unFocusedPageDrawable
*/
private void changePageIcon(int position, int pageIndex, ImageView indicatorImageView,
int focusedPageDrawable, int unFocusedPageDrawable) {
if (pageIndex == position) {
if (focusedPageDrawable != 0) {
indicatorImageView.setImageResource(focusedPageDrawable);
} else {
indicatorImageView.setImageResource(R.drawable.rounded_style_blue);
}
} else {
if (unFocusedPageDrawable != 0) {
indicatorImageView.setImageResource(unFocusedPageDrawable);
} else {
indicatorImageView.setImageResource(R.drawable.rounded_style2);
}
}
}
}
在您的回收站视图适配器中,您可以在下面通过界面添加替代
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
val manager = recyclerView.layoutManager
if (manager is LinearLayoutManager && itemCount > 0) {
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val visiblePosition: Int = manager.findFirstCompletelyVisibleItemPosition()
if (visiblePosition > -1) {
iFragmentCommunicator.updateCount(visiblePosition)
}
}
})
}
}
interface IFragmentCommunicator {
fun updateCount(count: Int)
}
最后在“活动”或“片段”中,您可以首先添加以下代码以调用“页面指示器”方法。
private fun initCircularIndicator() {
val margin =
(screenWidth - (0.8F * screenWidth).toInt()) / 2 - 8)
(mBinder?.llImageIndicator?.layoutParams as? FrameLayout.LayoutParams)?.apply {
setMargins(margin, 0, 0, 32))
}
mBinder?.llImageIndicator?.requestLayout()
mBinder?.llImageIndicator?.run {
removeAllViews()
createPageIndicator(
8,
R.drawable.selected_item_indicator,
0
)
handleViewPagerScroll(8, 0, R.drawable.selected_blue_item_indicator, 0)
}
}
在上面的代码中,您可以如下所示为selected_blue_item_indicator添加可绘制对象
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/color_brand" />
<corners android:radius="@dimen/four_dp" />
<size
android:width="@dimen/sixteen_dp"
android:height="@dimen/ten_dp" />
</shape>
,并且一旦您在Activity或Fragment中重写了updateCount()方法或调用页面指示器的handleViewPagerScroll()方法
override fun updateCount(count: Int) {
mBinder?.llImageIndicator?.handleViewPagerScroll(
8,
count,
R.drawable.selected_blue_item_indicator,
0
)
}
这就是您要做的一切。
答案 5 :(得分:1)
Shoban的答案对我不起作用,所以这就是我如何使它起作用。
请记住,我删除了动画,因为它们对于用例来说不是必需的。结果看起来就像这个问题中的屏幕截图一样。
此外,为了一次只滚动一个元素,我使用了PagerSnapHelper()来获得所需的结果。
PagerSnapHelper helper = new PagerSnapHelper();
helper.attachToRecyclerView(recyclerView);
recyclerView.addItemDecoration(new CirclePagerIndicatorDecoration());
这是我给装饰器的代码:
public class CirclePagerIndicatorDecoration extends RecyclerView.ItemDecoration {
private final int colorActive = 0xFFFFFFFF;
private final int colorInactive = 0x66FFFFFF;
private final int circleRadius = 8;
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(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, circleRadius, 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;
float highlightStart = indicatorStartX + itemWidth * highlightPosition;
if (progress == 0F) {
// no swipe, draw a normal indicator
c.drawCircle(highlightStart, indicatorPosY, circleRadius, mPaint);
}
}
@Override
public void getItemOffsets(@NotNull Rect outRect,
@NotNull View view,
@NotNull RecyclerView parent,
@NotNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.bottom = mIndicatorHeight;
}
答案 6 :(得分:0)
现在您可以使用ViewPager2。
它基本上包装了RecyclerView
(因此您将使用RecyclerView.Adapter
),但是它允许在TabLayoutMediator的帮助下附加TabLayout
。
然后可以将TabLayout
的样式设置为类似于点页面指示器。例如参见How do you create an Android View Pager with a dots indicator?
答案 7 :(得分:0)
实际上有一个非常好的图书馆。 只需将其添加到您的gradle依赖项
implementation "ru.tinkoff.scrollingpagerindicator:scrollingpagerindicator:1.0.6"
然后添加布局
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ru.tinkoff.scrollingpagerindicator.ScrollingPagerIndicator
android:id="@+id/indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
然后将指示器添加到您的回收站视图中
RecyclerView recyclerView = findViewById(R.id.recycler);
LayoutManager layoutManager = new LinearLayoutManager(this,
LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(layoutManager);
DemoRecyclerViewAdapter recyclerAdapter = new DemoRecyclerViewAdapter();
recyclerView.setAdapter(recyclerAdapter);
ScrollingPagerIndicator recyclerIndicator = findViewById(R.id.indicator);
recyclerIndicator.attachToRecyclerView(recyclerView);
答案 8 :(得分:0)
我对CirclePagerIndicatorDecoration进行了调整,因此它将支持RTL(从右至左)语言。我花了几天的时间,希望对您有所帮助:
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import androidx.annotation.ColorInt;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.Locale;
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(@ColorInt int colorInactive) {
mPaint.setStrokeWidth(mIndicatorStrokeWidth);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
colorActive = colorInactive;
}
@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;
if (isRtlLanguage()) {
activePosition = layoutManager.findLastVisibleItemPosition();
} else {
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);
if (isRtlLanguage()) {
indicatorStartX = (parent.getWidth() + indicatorTotalWidth) / 2F - (mIndicatorItemLength + DP * 4) / 2;
}
// float indicatorStartXhl = (parent.getWidth() + indicatorTotalWidth) / 2F - (mIndicatorItemLength + DP * 4) / 2;
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;
if (isRtlLanguage()) {
highlightStart = indicatorStartX - itemWidth * highlightPosition;
} else {
highlightStart = indicatorStartX + itemWidth * highlightPosition;
}
c.drawCircle(highlightStart, indicatorPosY, mIndicatorItemLength / 2F, mPaint);
} else {
float highlightStart;
if (isRtlLanguage()) {
highlightStart = indicatorStartX - itemWidth * highlightPosition;
} else {
highlightStart = indicatorStartX + itemWidth * highlightPosition;
}
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;
}
}
//The method that checks if it's RTL language:
private boolean isRtlLanguage() {
String deviceLanguage = Locale.getDefault().getLanguage();
return (deviceLanguage.contains("iw") || deviceLanguage.contains("ar")); //You can change here to your specific language
}
答案 9 :(得分:0)
如果有人在寻找 Xamarin.Android 解决方案,这是基于上述答案的解决方案:
public class RecyclerViewPageIndicator: RecyclerView.ItemDecoration
{
private readonly int size = ConvertDpToPixels(8);
private readonly int spacing = ConvertDpToPixels(10);
private readonly AccelerateDecelerateInterpolator interpolator;
private readonly Paint paint;
public RecyclerViewPageIndicator()
{
interpolator = new AccelerateDecelerateInterpolator();
paint = new Paint
{
AntiAlias = true,
StrokeCap = Paint.Cap.Round,
StrokeWidth = ConvertDpToPixels(2)
};
paint.SetStyle(Paint.Style.Fill);
}
public override void OnDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state)
{
base.OnDrawOver(c, parent, state);
var itemCount = parent.GetAdapter()?.ItemCount ?? 0;
var totalWidth = size * itemCount;
var totalSpacingWidth = Math.Max(0, itemCount - 1) * spacing;
var indicatorWidth = totalWidth + totalSpacingWidth;
var indicatorStartX = (parent.Width - indicatorWidth + size) / 2f;
var indicatorPosY = parent.Height - size * 2;
DrawInactiveIndicators(c, indicatorStartX, indicatorPosY, itemCount);
var layoutManager = (LinearLayoutManager)parent.GetLayoutManager();
var position = layoutManager.FindFirstVisibleItemPosition();
if (position == RecyclerView.NoPosition)
{
return;
}
var activeChild = layoutManager.FindViewByPosition(position);
var progress = interpolator.GetInterpolation(activeChild.Left * -1 / (float)activeChild.Width);
DrawHighlights(c, indicatorStartX, indicatorPosY, position, progress);
}
private void DrawInactiveIndicators(Canvas c, float indicatorStartX, float indicatorPosY, int itemCount)
{
paint.Color = Color.ParseColor("#D2E7F6");
var itemWidth = size + spacing;
var drawPosition = indicatorStartX;
for (var i = 0; i < itemCount; i++)
{
c.DrawCircle(drawPosition, indicatorPosY, size / 2f, paint);
drawPosition += itemWidth;
}
}
private void DrawHighlights(Canvas c, float indicatorStartX, float indicatorPosY, int position, float progress)
{
paint.Color = Color.ParseColor("#007AFF");
var itemWidth = size + spacing;
if (progress == 0)
{
var highlightStart = indicatorStartX + itemWidth * position;
c.DrawCircle(highlightStart, indicatorPosY, size / 2f, paint);
}
else
{
var highlightStart = indicatorStartX + itemWidth * position;
var partialLength = size * progress + spacing * progress;
c.DrawCircle(highlightStart + partialLength, indicatorPosY, size / 2f, paint);
}
}
public override void GetItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
{
base.GetItemOffsets(outRect, view, parent, state);
outRect.Bottom = size * 3;
}
private static int ConvertDpToPixels(int dpSize)
{
var scale = Resources.System.DisplayMetrics.Density;
return (int)(dpSize * scale + 0.5f);
}
}
答案 10 :(得分:-1)
首先,您必须为圈子创建另一个RecyclerView,并将此代码放在第一个RecyclerView的OnScrollListener中。
int[] firstVisibleItemPositions = new int[appList.size()];
int[] lastVisibleItemPositions = new int[appList.size()];
int position = ((StaggeredGridLayoutManager) listView.getLayoutManager()).findFirstVisibleItemPositions(firstVisibleItemPositions)[0];
View currentView = circlesList.getChildAt(position);
int lastPosition = ((StaggeredGridLayoutManager) listView.getLayoutManager()).findLastVisibleItemPositions(lastVisibleItemPositions)[0];
View lastView = circlesList.getChildAt(lastPosition);
ImageView circle;
if (dx>0) {
if (currentView != null && lastPosition != position) {
circle = (ImageView) currentView.findViewById(R.id.img);
circle.setImageResource(R.drawable.empty_circle);
}
if (lastView != null && lastPosition != position) {
circle = (ImageView) lastView.findViewById(R.id.img);
circle.setImageResource(R.drawable.selected_circle);
}
}else if (dx<0){
if (currentView != null && lastPosition != position) {
circle = (ImageView) currentView.findViewById(R.id.img);
circle.setImageResource(R.drawable.selected_circle);
}
if (lastView != null && lastPosition != position) {
circle = (ImageView) lastView.findViewById(R.id.img);
circle.setImageResource(R.drawable.empty_circle);
}
}