Android自定义View

年费比例控件

2017-09-16  本文已影响8人  aositeluoke

项目年费控件UI图


image.png

实现效果


年费.gif
控件分析(从里到外进行分析,最后分析指针)

1、中间有个红色圆点,抽取颜色和半径
2、白色圆环,抽取圆环宽度、圆环颜色
3、包围白色圆环的圆环宽度和颜色
4、指针指向的圆环颜色和宽度
5、进度圆弧的宽度、颜色和底色
6、最外边的圆弧颜色和宽度
7、指针颜色、长度和宽度
8、进度圆弧和最外层圆弧的距离
9、包围白色圆环的圆环和指针指向的圆环距离
10、绘制进度圆弧的开始角度为-225,扫描的最大度数为270
11、绘制指针时、先把画布旋转一定的角度再绘制

自定义属性
 <declare-styleable name="YearCostView">

        <!--centerPoint-->
        <attr name="center_point_color" format="color" />
        <attr name="center_point_radius" format="dimension" />

        <!--中间圆环的颜色和宽度-->
        <attr name="center_ring_color" format="color" />
        <attr name="center_ring_width" format="dimension" />

        <!--包裹中心圆环的圆环-->
        <attr name="wraper_center_ring_color" format="color" />
        <attr name="wraper_center_ring_width" format="dimension" />


        <!--指针-->
        <attr name="line_width" format="dimension" />
        <attr name="line_color" format="color" />


        <!--inner圆环-->
        <attr name="inner_ring_color" format="color" />
        <attr name="inner_ring_width" format="dimension" />

        <!--target圆环-->
        <attr name="target_ring_color" format="color" />
        <attr name="target_ring_width" format="dimension" />
        <attr name="target_bottom_ring_color" format="color" />

        <!--out圆环-->
        <attr name="out_ring_color" format="color" />
        <attr name="out_ring_width" format="dimension" />

        <!--距离-->
        <attr name="inner_distance" format="dimension" />
        <attr name="out_distance" format="dimension" />

    </declare-styleable>
获取自定义属性
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.YearCostView, defStyleAttr, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);

            switch (attr) {

                //中心圆点
                case R.styleable.YearCostView_center_point_radius:
                    centerPointRadius = a.getLayoutDimension(attr, centerPointRadius);
                    break;
                case R.styleable.YearCostView_center_point_color:
                    centerPointColor = a.getColor(attr, Color.parseColor("#f05b48"));
                    break;
                //中心圆环
                case R.styleable.YearCostView_center_ring_width:
                    centerRingWidth = a.getLayoutDimension(attr, centerRingWidth);
                    break;
                case R.styleable.YearCostView_center_ring_color:
                    centerRingColor = a.getColor(attr, ContextCompat.getColor(getContext(), android.R.color.white));
                    break;

                //包裹中心圆环的圆环
                case R.styleable.YearCostView_wraper_center_ring_width:
                    wraperCenterRingWidth = a.getLayoutDimension(attr, wraperCenterRingWidth);
                    break;
                case R.styleable.YearCostView_wraper_center_ring_color:
                    wraperCenterRingColor = a.getColor(attr, Color.parseColor("#35383c"));
                    break;

                //指针
                case R.styleable.YearCostView_line_width:
                    lineWidth = a.getLayoutDimension(attr, lineWidth);
                    break;
                case R.styleable.YearCostView_line_color:
                    lineColor = a.getColor(attr, Color.parseColor("#f05b48"));
                    break;

                //inner ring
                case R.styleable.YearCostView_inner_ring_width:
                    innerRingWidth = a.getLayoutDimension(attr, innerRingWidth);
                    break;
                case R.styleable.YearCostView_inner_ring_color:
                    innerRingColor = a.getColor(attr, Color.parseColor("#25292c"));
                    break;

                //target ring
                case R.styleable.YearCostView_target_ring_width:
                    targetRingWidth = a.getLayoutDimension(attr, targetRingWidth);
                    break;
                case R.styleable.YearCostView_target_ring_color:
                    targetRingColor = a.getColor(attr, Color.parseColor("#f05b48"));
                    break;
                case R.styleable.YearCostView_target_bottom_ring_color:
                    targetBottomRingColor = a.getColor(attr, Color.parseColor("#303438"));
                    break;

                //out ring
                case R.styleable.YearCostView_out_ring_width:
                    outRingWidth = a.getLayoutDimension(attr, outRingWidth);
                    break;
                case R.styleable.YearCostView_out_ring_color:
                    outRingColor = a.getColor(attr, Color.parseColor("#75777a"));
                    break;

                //距离
                case R.styleable.YearCostView_out_distance:
                    outDistance = a.getLayoutDimension(attr, outDistance);
                    break;
                case R.styleable.YearCostView_inner_distance:
                    innerDistance = a.getLayoutDimension(attr, innerDistance);
                    break;
            }
        }
        a.recycle();
自定义控件完整代码
/**
 * 类描述:年费View
 * 作者:xues
 * 时间:2017年09月12日
 */

public class YearCostView extends View {

    //中心圆环(白色圆环)
    private Paint centerRingPaint;
    private int centerRingWidth = 2 * 6;
    private int centerRingColor;
    private RectF centerRingRectF;

    //包裹中心圆环的圆环
    private int wraperCenterRingColor;
    private Paint wraperCenterRingPaint;
    private int wraperCenterRingWidth = 4 * 6;
    private RectF wraperCenterRingRectF;


    //在目标圆环里边的圆环
    private int innerRingColor;
    private Paint innerRingPaint;
    private int innerRingWidth = 1 * 6;
    private RectF innerRingRectF;

    //目标圆环(红色圆环)
    private int targetRingColor;
    private Paint targetRingPaint;
    private int targetRingWidth = 16 * 6;
    private RectF targetRingRectF;

    //目标圆环压着的圆环(红色圆环压着的圆环)
    private int targetBottomRingColor;
    private Paint targetBottomRingPaint;
    private int targetBottomRingWidth = 16 * 6;
    private RectF targetBottomRingRectF;


    //在目标圆环外面的圆环
    private int outRingColor;
    private Paint outRingPaint;
    private int outRingWidth = 1 * 6;
    private RectF outRingRectF;


    //指针
    private int lineColor;
    private Paint linePaint;
    private int lineWidth = 2 * 6;

    //中心红点
    private int centerPointColor;
    private Paint centerPointPaint;
    private int centerPointRadius = 1 * 6;


    //圆环与圆环之间的距离
    private int innerDistance = 120;
    private int outDistance = 8;
    private RotateAnimation mSweepAnim;//扫描动画

    public YearCostView(Context context) {
        this(context, null);
    }

    public YearCostView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public YearCostView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.YearCostView, defStyleAttr, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);

            switch (attr) {

                //中心圆点
                case R.styleable.YearCostView_center_point_radius:
                    centerPointRadius = a.getLayoutDimension(attr, centerPointRadius);
                    break;
                case R.styleable.YearCostView_center_point_color:
                    centerPointColor = a.getColor(attr, Color.parseColor("#f05b48"));
                    break;
                //中心圆环
                case R.styleable.YearCostView_center_ring_width:
                    centerRingWidth = a.getLayoutDimension(attr, centerRingWidth);
                    break;
                case R.styleable.YearCostView_center_ring_color:
                    centerRingColor = a.getColor(attr, ContextCompat.getColor(getContext(), android.R.color.white));
                    break;

                //包裹中心圆环的圆环
                case R.styleable.YearCostView_wraper_center_ring_width:
                    wraperCenterRingWidth = a.getLayoutDimension(attr, wraperCenterRingWidth);
                    break;
                case R.styleable.YearCostView_wraper_center_ring_color:
                    wraperCenterRingColor = a.getColor(attr, Color.parseColor("#35383c"));
                    break;

                //指针
                case R.styleable.YearCostView_line_width:
                    lineWidth = a.getLayoutDimension(attr, lineWidth);
                    break;
                case R.styleable.YearCostView_line_color:
                    lineColor = a.getColor(attr, Color.parseColor("#f05b48"));
                    break;

                //inner ring
                case R.styleable.YearCostView_inner_ring_width:
                    innerRingWidth = a.getLayoutDimension(attr, innerRingWidth);
                    break;
                case R.styleable.YearCostView_inner_ring_color:
                    innerRingColor = a.getColor(attr, Color.parseColor("#25292c"));
                    break;

                //target ring
                case R.styleable.YearCostView_target_ring_width:
                    targetRingWidth = a.getLayoutDimension(attr, targetRingWidth);
                    break;
                case R.styleable.YearCostView_target_ring_color:
                    targetRingColor = a.getColor(attr, Color.parseColor("#f05b48"));
                    break;
                case R.styleable.YearCostView_target_bottom_ring_color:
                    targetBottomRingColor = a.getColor(attr, Color.parseColor("#303438"));
                    break;

                //out ring
                case R.styleable.YearCostView_out_ring_width:
                    outRingWidth = a.getLayoutDimension(attr, outRingWidth);
                    break;
                case R.styleable.YearCostView_out_ring_color:
                    outRingColor = a.getColor(attr, Color.parseColor("#75777a"));
                    break;

                //距离
                case R.styleable.YearCostView_out_distance:
                    outDistance = a.getLayoutDimension(attr, outDistance);
                    break;
                case R.styleable.YearCostView_inner_distance:
                    innerDistance = a.getLayoutDimension(attr, innerDistance);
                    break;
            }
        }
        a.recycle();
        initView();
    }

    /**
     * 初始化参数
     */
    private void initView() {
        initPaint();
        //初始化动画并设置动画持续时间为1000毫秒==1秒
        mSweepAnim = new RotateAnimation();
        mSweepAnim.setDuration(1000);
    }

    float centerX;//中心点x

    //初始化矩形
    private void initRectF() {
        //中心圆环
        float leftOrTop = centerX - centerRingWidth / 2F - centerPointRadius;
        float rightOrBottom = centerX + centerRingWidth / 2F + centerPointRadius;
        centerRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);
        //包围中心圆环的圆环
        leftOrTop = centerX - centerRingWidth - centerPointRadius - wraperCenterRingWidth / 2F;
        rightOrBottom = centerX + centerRingWidth + centerPointRadius + wraperCenterRingWidth / 2F;
        wraperCenterRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);
        //inner圆环
        leftOrTop = centerX - centerPointRadius - centerRingWidth - wraperCenterRingWidth - innerDistance - innerRingWidth / 2F;
        rightOrBottom = centerX + centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth / 2F;
        innerRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);

        //目标圆环
        leftOrTop = centerX - centerPointRadius - centerRingWidth - wraperCenterRingWidth - innerDistance - innerRingWidth - outDistance - targetRingWidth / 2F;
        rightOrBottom = centerX + centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth + outDistance + targetRingWidth / 2F;
        targetRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);
        targetBottomRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);

        //out圆环
        leftOrTop = centerX - centerPointRadius - centerRingWidth - wraperCenterRingWidth - innerDistance - innerRingWidth - outDistance * 2 - targetRingWidth - outRingWidth / 2F;
        rightOrBottom = centerX + centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth + outDistance * 2 + targetRingWidth + outRingWidth / 2F;
        outRingRectF = new RectF(leftOrTop, leftOrTop, rightOrBottom, rightOrBottom);

    }

    /**
     * 从里边向外初始化画笔
     */
    private void initPaint() {
        //中心点
        centerPointPaint = new Paint();
        centerPointPaint.setAntiAlias(true);
        centerPointPaint.setStrokeWidth(2 * centerPointRadius);
        centerPointPaint.setColor(centerPointColor);
        centerPointPaint.setStyle(Paint.Style.FILL);
        //中心圆环
        centerRingPaint = new Paint();
        centerRingPaint.setAntiAlias(true);
        centerRingPaint.setStrokeWidth(centerRingWidth);
        centerRingPaint.setColor(centerRingColor);
        centerRingPaint.setStyle(Paint.Style.STROKE);
        //包裹中心圆环的圆环
        wraperCenterRingPaint = new Paint();
        wraperCenterRingPaint.setAntiAlias(true);
        wraperCenterRingPaint.setStrokeWidth(wraperCenterRingWidth);
        wraperCenterRingPaint.setColor(wraperCenterRingColor);
        wraperCenterRingPaint.setStyle(Paint.Style.STROKE);

        //inner圆环
        innerRingPaint = new Paint();
        innerRingPaint.setAntiAlias(true);
        innerRingPaint.setStrokeWidth(innerRingWidth);
        innerRingPaint.setColor(innerRingColor);
        innerRingPaint.setStyle(Paint.Style.STROKE);


        //目标圆环压住的圆环
        targetBottomRingPaint = new Paint();
        targetBottomRingPaint.setAntiAlias(true);
        targetBottomRingPaint.setStrokeWidth(targetRingWidth);
        targetBottomRingPaint.setColor(targetBottomRingColor);
        targetBottomRingPaint.setStyle(Paint.Style.STROKE);

        //目标圆环
        targetRingPaint = new Paint();
        targetRingPaint.setAntiAlias(true);
        targetRingPaint.setStrokeWidth(targetRingWidth);
        targetRingPaint.setColor(targetRingColor);
        targetRingPaint.setStyle(Paint.Style.STROKE);

        //外部圆环
        outRingPaint = new Paint();
        outRingPaint.setAntiAlias(true);
        outRingPaint.setStrokeWidth(outRingWidth);
        outRingPaint.setColor(outRingColor);
        outRingPaint.setStyle(Paint.Style.STROKE);

        //指针
        linePaint = new Paint();
        linePaint.setAntiAlias(true);
        linePaint.setStrokeWidth(lineWidth);
        linePaint.setColor(lineColor);
        linePaint.setStyle(Paint.Style.FILL);

    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int wSize = 0;


        //match_parent or set value
        if (widthMode == MeasureSpec.EXACTLY) {
            wSize = widthSize;
        } else {
            //wrap_content
            if (widthMode == MeasureSpec.AT_MOST) {
                wSize = 2 * (centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth + outDistance * 2 + targetRingWidth);
            }
        }


        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int hSize = 0;

        //match_parent or set value
        if (heightMode == MeasureSpec.EXACTLY) {
            hSize = heightSize;
        } else {
            //wrap_content
            if (heightMode == MeasureSpec.AT_MOST) {
                hSize = 2 * (centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth + outDistance * 2 + targetRingWidth);
                ;
            }
        }

        centerX = widthSize / 2f;
        initRectF();//初始化灰色圆环和多颜色圆环矩形
        setMeasuredDimension(wSize, hSize);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        //绘制中心点
        canvas.save();
        canvas.restore();

        //绘制包裹中心圆环的圆环
        canvas.save();
        canvas.drawArc(wraperCenterRingRectF, 0, 360, false, wraperCenterRingPaint);
        canvas.restore();

        //绘制inner圆环
        canvas.save();
        canvas.drawArc(innerRingRectF, 0, 360, false, innerRingPaint);
        canvas.restore();
        //绘制指针
        canvas.save();
        canvas.translate(centerX, centerX);
        canvas.rotate(mSweepAngle + 135);
        canvas.drawLine(-2, -2, centerPointRadius + centerRingWidth + wraperCenterRingWidth + innerDistance + innerRingWidth, 0, linePaint);
        canvas.restore();

        //绘制中心圆环
        canvas.save();
        canvas.drawArc(centerRingRectF, 0, 360, false, centerRingPaint);
        canvas.restore();


        //绘制红色圆点
        canvas.save();
        canvas.drawCircle(centerX, centerX, centerPointRadius, centerPointPaint);
        canvas.restore();


        //绘制目标圆环压住的圆环
        canvas.save();
        canvas.drawArc(targetBottomRingRectF, -225, 270, false, targetBottomRingPaint);
        canvas.restore();

        //绘制目标圆环
        canvas.save();
        canvas.drawArc(targetRingRectF, -225, mSweepAngle, false, targetRingPaint);
        canvas.restore();


        //绘制out圆环
        canvas.save();
        canvas.drawArc(outRingRectF, -226, 272, false, outRingPaint);
        canvas.restore();
    }


    float mSweepAngle;

    /**
     * 自定义旋转动画
     */
    public class RotateAnimation extends Animation {
        /**
         * Initializes expand collapse animation, has two types, collapse (1) and expand (0).
         */
        public RotateAnimation() {
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            //interpolatedTime 范围:0到1
            mSweepAngle = BigDecimalUtil.mul(interpolatedTime, BigDecimalUtil.mul(BigDecimalUtil.div(curMoney, totalMoney), 270F));//当前时间扫描的角度
            postInvalidate();//重绘
        }
    }


    float curMoney, totalMoney;

    /**
     * 设置价格
     *
     * @param curMoney   当前价格
     * @param totalMoney 总金额
     */
    public void setMoney(float curMoney, float totalMoney) {
        this.curMoney = curMoney;
        this.totalMoney = totalMoney;
        startAnimation(mSweepAnim);
    }
}
使用篇

在布局中使用自定义控件

<包名.YearCostView
        android:id="@+id/yearCostView"
        android:layout_width="@dimen/px480dp"
        android:layout_height="@dimen/px480dp"
        android:layout_gravity="center"
        android:background="#191d21"
        app:center_point_color="#f05b48"
        app:center_point_radius="@dimen/px6dp"
        app:center_ring_color="#ffffff"
        app:center_ring_width="@dimen/px6dp"
        app:inner_distance="@dimen/px100dp"
        app:inner_ring_color="#25292c"
        app:inner_ring_width="@dimen/px2dp"
        app:line_color="#f05b48"
        app:line_width="@dimen/px6dp"
        app:out_distance="@dimen/px10dp"
        app:out_ring_color="#75777a"
        app:out_ring_width="@dimen/px2dp"
        app:target_bottom_ring_color="#303438"
        app:target_ring_color="#f05b48"
        app:target_ring_width="@dimen/px64dp"
        app:wraper_center_ring_color="#35383c"
        app:wraper_center_ring_width="@dimen/px12dp" />

在Activity中设置价格

yearCostView.setMoney(135,270);//左侧为当前金额,右侧为总金额
上一篇下一篇

猜你喜欢

热点阅读