一个values文件
attrs_universal_indicator.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="Indicator"><!--未选中的指示器颜色--><attr name="normal_color" format="reference|color" /><!--选中的指示器颜色--><attr name="selected_color" format="reference|color" /><!--指示器每个item之间的间距--><attr name="spacing" format="dimension" /><!--指示器排列方向--><attr name="orientation" format="enum"><enum name="horizontal" value="0" /><enum name="vertical" value="1" /></attr><!--指示器类型 命名规则:未选中样式_选中样式--><attr name="style" format="enum"><!--都是圆点--><enum name="circle_circle" value="0"/><!--都是方形--><enum name="rect_rect" value="1" /><!--未选中是圆点,选中是方形--><enum name="circle_rect" value="2" /></attr><!--都是圆点指示器半径大小--><attr name="circle_circle_radius" format="dimension" /><!--都是方形指示器长度--><attr name="rect_rect_itemWidth" format="dimension" /><!--都是方形指示器高度--><attr name="rect_rect_itemHeight" format="dimension" /><!--都是方形指示器圆角--><attr name="rect_rect_corner" format="dimension" /><!--circle_rect 模式圆点半径--><attr name="circle_rect_radius" format="dimension" /><!--circle_rect 模式方形宽度--><attr name="circle_rect_itemWidth" format="dimension" /><!--circle_rect 模式方形高度--><attr name="circle_rect_itemHeight" format="dimension" /><!--circle_rect 模式方形圆角--><attr name="circle_rect_corner" format="dimension" /></declare-styleable>
</resources>
自定义view类UIndicator
/*** 作者:created by meixi* 邮箱:1085220040@qq.com* 日期:2020/1/6 10:41*/public class UIndicator extends View implements ViewPager.OnPageChangeListener {private static final String TAG = "UIndicator";//指示器样式一 选中未选中都是圆点public static final int STYLE_CIRCLR_CIRCLE = 0;//指示器样式二 选中未选中都是方形public static final int STYLE_RECT_RECT = 1;//指示器样式三 选中方形,未选中圆点public static final int STYLE_CIRCLR_RECT = 2;//横向排列public static final int HORIZONTAL = 0;//纵向排列public static final int VERTICAL = 1;private Context mContext;//指示器之间的间距private int spacing;//指示器排列方向private int orientation = HORIZONTAL;//选中与为选中的颜色private ColorStateList selectedColor, normalColor;//指示器样式,默认都是圆点private int mStyle = STYLE_CIRCLR_CIRCLE;//样式一 圆点半径大小private int circleCircleRadius = 0;//样式二 方形大小及圆角private int rectRectItemWidth = 0, rectRectItemHeight = 0, rectRectCorner = 0;//样式三 选中的方形大小及圆角private int circleRectItemWidth = 0, circleRectItemHeight = 0, circleRectCorner = 0;//样式三 未选中的圆点半径private int circleRectRadius = 0;//画笔private Paint normalPaint, selectedPaint;//指示器item的区域private RectF mRectF;//指示器大小private int width, height;//指示器item个数private int itemCount = 0;//当前选中的位置private int selection = 0;private ViewPager viewPager;public UIndicator(Context context) {this(context, null);}public UIndicator(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public UIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mContext = context;init(attrs);intPaint();checkItemCount();}/*** 加载自定义属性*/private void init(AttributeSet attrs) {// 加载自定义属性集合TypedArray ta = mContext.obtainStyledAttributes(attrs, R.styleable.Indicator);// 第二个参数是默认设置颜色selectedColor = ta.getColorStateList(R.styleable.Indicator_selected_color);normalColor = ta.getColorStateList(R.styleable.Indicator_normal_color);spacing = ta.getDimensionPixelSize(R.styleable.Indicator_spacing, dip2px(6));//6orientation = ta.getInt(R.styleable.Indicator_orientation, HORIZONTAL);mStyle = ta.getInt(R.styleable.Indicator_style, STYLE_CIRCLR_CIRCLE);circleCircleRadius = ta.getDimensionPixelSize(R.styleable.Indicator_circle_circle_radius, dip2px(3));rectRectCorner = ta.getDimensionPixelSize(R.styleable.Indicator_rect_rect_corner, 0);rectRectItemHeight = ta.getDimensionPixelSize(R.styleable.Indicator_rect_rect_itemHeight, dip2px(3));rectRectItemWidth = ta.getDimensionPixelSize(R.styleable.Indicator_rect_rect_itemWidth, dip2px(15));circleRectCorner = ta.getDimensionPixelSize(R.styleable.Indicator_circle_rect_corner, 0);circleRectRadius = ta.getDimensionPixelSize(R.styleable.Indicator_circle_rect_radius, dip2px(3));//3circleRectItemHeight = ta.getDimensionPixelSize(R.styleable.Indicator_circle_rect_itemHeight, dip2px(3));circleRectItemWidth = ta.getDimensionPixelSize(R.styleable.Indicator_circle_rect_itemWidth, dip2px(15));// 解析后释放资源ta.recycle();}private void intPaint() {normalPaint = new Paint();normalPaint.setStyle(Paint.Style.FILL);normalPaint.setAntiAlias(true);normalPaint.setColor(normalColor == null ? Color.GRAY : normalColor.getDefaultColor());selectedPaint = new Paint();selectedPaint.setStyle(Paint.Style.FILL);selectedPaint.setAntiAlias(true);selectedPaint.setColor(selectedColor == null ? Color.RED : selectedColor.getDefaultColor());mRectF = new RectF();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);switch (mStyle) {case STYLE_CIRCLR_CIRCLE:if (orientation == HORIZONTAL){width = 2 * circleCircleRadius * itemCount + (itemCount - 1) * spacing;height = Math.max(heightSize, 2 * circleCircleRadius);} else {height = 2 * circleCircleRadius * itemCount + (itemCount - 1) * spacing;width = Math.max(widthSize, 2 * circleCircleRadius);}break;case STYLE_RECT_RECT:if (orientation == HORIZONTAL){width = rectRectItemWidth * itemCount + (itemCount - 1) * spacing;height = Math.max(heightSize, rectRectItemHeight);} else {height = rectRectItemHeight * itemCount + (itemCount - 1) * spacing;width = Math.max(widthSize, rectRectItemWidth);}break;case STYLE_CIRCLR_RECT:if (orientation == HORIZONTAL){int normalItemWidth = circleRectRadius * 2;width = (itemCount - 1) * normalItemWidth + circleRectItemWidth + (itemCount - 1) * spacing;int tempHeight = Math.max(circleRectItemHeight, circleRectRadius * 2);height = Math.max(heightSize, tempHeight);} else {int normalItemHeight = circleRectRadius * 2;height = (itemCount - 1) * normalItemHeight + circleRectItemHeight + (itemCount - 1) * spacing;int tempWidth = Math.max(circleRectItemWidth, circleRectRadius * 2);width = Math.max(widthSize, tempWidth);}break;}setMeasuredDimension(width, height);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (orientation == HORIZONTAL) {switch (mStyle) {case STYLE_CIRCLR_CIRCLE:float cy = height / 2;for (int i = 0; i < itemCount; i++) {int cx = (i + 1) * circleCircleRadius + i * spacing;//全部绘制圆点,画笔的区别canvas.drawCircle(cx, cy, circleCircleRadius, i == selection ? selectedPaint : normalPaint);}break;case STYLE_RECT_RECT:for (int i = 0; i < itemCount; i++) {int left = i * rectRectItemWidth + i * spacing;mRectF.set(left, 0, left + rectRectItemWidth, rectRectItemHeight);//全部绘制圆角矩形,画笔的区别canvas.drawRoundRect(mRectF, rectRectCorner, rectRectCorner, i == selection ? selectedPaint : normalPaint);}break;case STYLE_CIRCLR_RECT:for (int i = 0; i < itemCount; i++) {int left = selection * (circleRectRadius * 2 + spacing);int top;if (selection == i) {//选中的绘制圆角矩形top = (height - circleRectItemHeight) / 2;mRectF.set(left, top, left + circleRectItemWidth, circleRectItemHeight + top);canvas.drawRoundRect(mRectF, circleRectCorner, circleRectCorner, selectedPaint);} else {//未选中的绘制圆点,距离需要判断position在选中的左边或者右边,从而确定cxtop = (height - circleRectRadius * 2) / 2;int cx = 0;float cy1 = circleRectRadius + top;if (selection < i) {cx = (i - 1) * circleRectRadius * 2 + i * spacing + circleRectItemWidth + circleRectRadius;} else {cx = i * (circleRectRadius * 2) + i * spacing + circleRectRadius;}canvas.drawCircle(cx, cy1, circleRectRadius, normalPaint);}}break;}} else {switch (mStyle) {case STYLE_CIRCLR_CIRCLE:float cx = width / 2;for (int i = 0; i < itemCount; i++) {int cy = i * (circleCircleRadius * 2 + spacing)+ circleCircleRadius;//全部绘制圆点,画笔的区别canvas.drawCircle(cx, cy, circleCircleRadius, i == selection ? selectedPaint : normalPaint);}break;case STYLE_RECT_RECT:for (int i = 0; i < itemCount; i++) {int top = i * rectRectItemHeight + i * spacing;int left = (width - rectRectItemWidth) / 2;mRectF.set(left, top, left + rectRectItemWidth, top + rectRectItemHeight);//全部绘制圆角矩形,画笔的区别canvas.drawRoundRect(mRectF, rectRectCorner, rectRectCorner, i == selection ? selectedPaint : normalPaint);}break;case STYLE_CIRCLR_RECT:for (int i = 0; i < itemCount; i++) {if (selection == i) {int left = (width - circleRectItemWidth) / 2;//选中的绘制圆角矩形int top = selection * (circleRectRadius * 2 + spacing);mRectF.set(left, top, left + circleRectItemWidth, top + circleRectItemHeight);canvas.drawRoundRect(mRectF, circleRectCorner, circleRectCorner, selectedPaint);} else {//未选中的绘制圆点,距离需要判断position在选中的左边或者右边,从而确定cxint cx1 = (width - 2 * circleRectRadius) / 2 + circleRectRadius;float cy1 = 0;if (selection < i) {cy1 = (i - 1) * circleRectRadius * 2 + i * spacing + circleRectItemHeight + circleRectRadius;} else {cy1 = i * (circleRectRadius * 2) + i * spacing + circleRectRadius;}canvas.drawCircle(cx1, cy1, circleRectRadius, normalPaint);}}break;}}}/*** 关联ViewPager** @param viewPager*/public void attachToViewPager(ViewPager viewPager) {this.viewPager = viewPager;PagerAdapter pagerAdapter = viewPager.getAdapter();if (pagerAdapter != null) {//TODO 如果项目使用了阿里开源库,UltraViewPager,想要兼容需要用以下方式获取 itemCount,否则去除这个if条件if (pagerAdapter instanceof UltraViewPagerAdapter) {//从UltraViewPagerAdapter获取真实的个数itemCount = ((UltraViewPagerAdapter) pagerAdapter).getRealCount();} else {itemCount = pagerAdapter.getCount();}selection = viewPager.getCurrentItem() % itemCount;checkItemCount();}viewPager.addOnPageChangeListener(this);}/*** 设置选中的值,当ViewPager只有一个item不显示指示器*/private void checkItemCount() {if (selection >= itemCount) {selection = itemCount - 1;}setVisibility((itemCount <= 1) ? GONE : VISIBLE);}@Overridepublic void onPageSelected(int i) {if (viewPager != null) {PagerAdapter pagerAdapter = viewPager.getAdapter();if (pagerAdapter != null) {selection = viewPager.getCurrentItem() % itemCount;}}postInvalidate();}@Overridepublic void onPageScrolled(int i, float v, int i1) {}@Overridepublic void onPageScrollStateChanged(int i) {}/*** dp to px*/public int dip2px(float dpValue) {final float scale = getContext().getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}
}
Activity代码
public class ViewPagerActivity extends Activity {private ViewPager vp;private UIndicator uIndicator1;
vp = findViewById(R.id.vp_guide);
uIndicator1 = findViewById(R.id.indicator1);
uIndicator1.attachToViewPager(vp);
vp.setAdapter(mAdapter);在attachToViewPager之前
附:layout调用自定义view
<com.tianxin.okhttptest.viewpg.UIndicatorandroid:id="@+id/indicator1"android:layout_width="match_parent"android:layout_height="6dp"android:layout_gravity="bottom|center_horizontal"android:layout_marginTop="10dp"app:circle_circle_radius="3dp"app:normal_color="#99ffffff"app:selected_color="#ffffff"app:spacing="10dp"app:style="circle_rect" />