![](https://img2020.cnblogs.com/blog/2420771/202201/2420771-20220117150828039-1677750994.png)
IndicatorView
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.Nullable;
import androidx.viewpager.widget.ViewPager;
/**
* @author:https://www.jianshu.com/p/1235c5d37d73?tdsourcetag=s_pcqq_aiomsg
* @author Administrator : https://www.jianshu.com/p/0c55a71c7676
* ViewPager 圆球指示器
*/
public class IndicatorView extends View {
private Context mContext;
private int childCount; // 小球数量
private int selectPosition; //被选中的小球position
private int scrollPosition; //这个是滑动的时候 要到达的position
private float ratio; // 比率
private int dotSpace = 8; // 球之间的空隙
private int radius = 4; // 球半径
private List<DotView> mDotViews; // dot's list
private DotBarView barView;
private Paint dotPaint;
private Paint selectDotPaint;
public IndicatorView(Context context) {
this(context, null);
}
public IndicatorView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//init
mContext = context;
dotPaint = new Paint();
dotPaint.setAntiAlias(true);
dotPaint.setColor(Color.GREEN);
selectDotPaint = new Paint();
selectDotPaint.setAntiAlias(true);
selectDotPaint.setColor(Color.RED);
}
/**
* 初始化Dot
*/
private void initDot() {
mDotViews = new ArrayList<>();
for (int i = 0; i < childCount; i++) {
//new
DotView dotView = new DotView();
mDotViews.add(dotView);
}
//初始化滑块
barView = new DotBarView();
}
/**
* 关联ViewPager
*/
public void setViewPager(ViewPager viewPager) {
//圆点个数
childCount = viewPager.getAdapter().getCount();
Log.d("tww","childCOunt:"+childCount);
//初始化
initDot();
//@ positionOffset: Value from [0, 1) indicating the offset from the page at position.
//positionOffset 来自 [0, 1) 的值,表示从页面位置的偏移量。
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
scrollPosition = position;//滑动时
Log.d("tww", "position:" + position + ", positionOffset:" + positionOffset + ", " +
"positionOffsetPixels:" + positionOffsetPixels);
//偏移量
ratio = positionOffset;
if (ratio >= 1 || ratio <= 0) {
return;
}
//计算小球和滑块移动的距离,产生相应的动画效果
compute();
invalidate();
}
@Override
public void onPageSelected(int position) {
selectPosition = position;//选中时
ratio = 0;
compute();
invalidate();
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
//默认
ratio = 0;
compute();
invalidate();
}
/**
* 绘制小球的位置,计算
*/
private void compute() {
//计算完调用 invalidate(),自动重绘页面,调用 view 的 onDraw() 方法
//初始化确定球的位置
for (int i = 0; i < mDotViews.size(); i++) {
DotView dotView = mDotViews.get(i);
dotView.radius = radius;
dotView.x = radius * 2 * (i + 1) + dotSpace * i;//x 水平距离 radius *2 直径
dotView.y = radius;
dotView.isChecked = selectPosition == i;
}
//计算bar的位置 获取选中的DotView 看左右两边的跟其他DotView的距离
DotView selectDotView = mDotViews.get(selectPosition);
int selectX = selectDotView.x;
int selectY = selectDotView.y;
//判断是往左滑还是右滑
if (selectPosition <= scrollPosition) {
//往右是增加右边圆的圆心
barView.leftX = selectX;
barView.leftY = selectY;
barView.rightX = (int) (selectX + (2 * radius + dotSpace) * ratio);//右滑动的距离 ratio viewpager滑动的偏移量
barView.rightY = selectY;
barView.radius = radius;
}else{
//-
barView.rightX = selectX;
barView.rightY = selectY;
barView.leftX = (int) (selectX - (2 * radius + dotSpace) * (1 - ratio));//左滑动的距离
barView.leftY = selectY;
barView.radius = radius;
}
}
/**
*
* compute2
*/
private void compute2(){
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//draw dot
for(DotView dotView:mDotViews){
canvas.drawCircle(dotView.x,dotView.y,dotView.radius,dotView.isChecked?selectDotPaint:dotPaint);
}
//画bar的头尾圆
canvas.drawCircle(barView.leftX, barView.leftY, barView.radius, selectDotPaint);
canvas.drawCircle(barView.rightX, barView.rightY, barView.radius, selectDotPaint);
//画bar的中间rect
canvas.drawRect(new RectF(barView.leftX, 0, barView.rightX, radius * 2), selectDotPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//设置view宽高 不设置就是默认全屏view,没办法改变位置
if(mDotViews != null && mDotViews.size() > 0) {
int width = mDotViews.get(mDotViews.size() - 1).x + radius;
int height = radius * 2;
setMeasuredDimension(width, height);
}else{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
/**
* 圆点对象
*/
public class DotView {
private int x;
private int y;
private int radius;
private boolean isChecked;//是否被选中
}
/**
* 滑动时,产生动画的View(对象)
*/
public class DotBarView {
private int leftX;
private int leftY;
private int rightX;
private int rightY;
private int radius;
}
}