Android ViewPager指示器

一个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));//6
        orientation = 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));//3
        circleRectItemHeight = 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();
    }


    @Override
    protected 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);
    }

    @Override
    protected 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在选中的左边或者右边,从而确定cx
                            top = (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在选中的左边或者右边,从而确定cx
                            int 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);
    }

    @Override
    public void onPageSelected(int i) {
        if (viewPager != null) {
            PagerAdapter pagerAdapter = viewPager.getAdapter();
            if (pagerAdapter != null) {
                selection = viewPager.getCurrentItem() % itemCount;
            }
        }
        postInvalidate();
    }

    @Override
    public void onPageScrolled(int i, float v, int i1) {

    }


    @Override
    public 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.UIndicator
    android: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" />
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值