android 自定义pm2.5进度显示圆环

 
public  class Pm2.5CircleView extend View {
private int mWidth;
    private int mHeight;
    private int diameter = 500;  //直径
    private float centerX;  //圆心X坐标
    private float centerY;  //圆心Y坐标

    private Paint allArcPaint;
    private Paint progressPaint;
    private Paint vTextPaint;
    private Paint hintPaint;
    private Paint degreePaint;
    private Paint curSpeedPaint;

    private RectF bgRect;

    private ValueAnimator progressAnimator;
    private PaintFlagsDrawFilter mDrawFilter;
    private SweepGradient sweepGradient;
    private Matrix rotateMatrix;

    private float startAngle = 105;
    private float sweepAngle = 270;
    private float currentAngle = 330; //105 - 330
    private float lastAngle;
    private int[] colors = new int[]{Color.GREEN, Color.YELLOW, Color.RED, Color.RED};
    private float maxValues = 60;
    private float curValues = 100;
    private float bgArcWidth = dipToPx(2);
    private float progressWidth = dipToPx(10);
    private float textSize = dipToPx(60);
    private float hintSize = dipToPx(15);
    private float curSpeedSize = dipToPx(13);
    private int aniSpeed = 1000;
    private float longdegree = dipToPx(13);
    private float shortdegree = dipToPx(5);
    private final int DEGREE_PROGRESS_DISTANCE = dipToPx(8);

    private String hintColor = "#676767";
    private String longDegreeColor = "#111111";
    private String shortDegreeColor = "#111111";
    private String bgArcColor = "#111111";
    private String titleString;
    private String hintString;

    private boolean isShowCurrentSpeed = true;
    private boolean isNeedTitle;
    private boolean isNeedUnit;
    private boolean isNeedDial;
    private boolean isNeedContent;
    private Drawable mThumb, mThumbPress;
    private int paddingOuterThumb;

    // sweepAngle / maxValues 的值
    private float k;
    private Paint vTextPaint_zhi;
    private RectF oval;
    private float radius;//圆环半径

    /**
     * 当前进度
     */
    private int progress = 190;//最大对应498-150刻度
    //progress = 310(实际值) - 0刻度
    //progress =375(实际值) - 50(对应虚拟刻度(pm2.5)    //progress =439(实际值) - 100(对应虚拟刻度(pm2.5)    //progress =498(实际值) - 150(对应虚拟刻度(pm2.5)    //progress =61 (实际值)- 200(对应虚拟刻度(pm2.5)    //progress =124(实际值) - 250(对应虚拟刻度(pm2.5)    //progress =190(实际值) - 500(对应虚拟刻度(pm2.5)
    public ColorArcProgressBar(Context context) {
        super(context, null);
        initView();
    }


    public ColorArcProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
        initCofig(context, attrs);
        initView();
    }

    public ColorArcProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initCofig(context, attrs);
        initView();
    }

    /**
     * 初始化布局配置
     * @param context
     * @param attrs
     */
    private void initCofig(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ColorArcProgressBar);
        int color1 = a.getColor(R.styleable.ColorArcProgressBar_front_color1, Color.GREEN);
        int color2 = a.getColor(R.styleable.ColorArcProgressBar_front_color2, color1);
        int color3 = a.getColor(R.styleable.ColorArcProgressBar_front_color3, color1);
        int color4 = a.getColor(R.styleable.ColorArcProgressBar_front_color4, color1);
        int color5 = a.getColor(R.styleable.ColorArcProgressBar_front_color5, color1);
        colors = new int[]{color1, color2, color3,color4, color5,color1};

        sweepAngle = a.getInteger(R.styleable.ColorArcProgressBar_total_engle, 270);
        bgArcWidth = a.getDimension(R.styleable.ColorArcProgressBar_back_width, dipToPx(2));
        progressWidth = a.getDimension(R.styleable.ColorArcProgressBar_front_width, dipToPx(10));
        isNeedTitle = a.getBoolean(R.styleable.ColorArcProgressBar_is_need_title, false);
        isNeedContent = a.getBoolean(R.styleable.ColorArcProgressBar_is_need_content, false);
        isNeedUnit = a.getBoolean(R.styleable.ColorArcProgressBar_is_need_unit, false);
        isNeedDial = a.getBoolean(R.styleable.ColorArcProgressBar_is_need_dial, false);
        hintString = a.getString(R.styleable.ColorArcProgressBar_string_unit);
        titleString = a.getString(R.styleable.ColorArcProgressBar_string_title);
        curValues = a.getFloat(R.styleable.ColorArcProgressBar_current_value, 100);
        maxValues = a.getFloat(R.styleable.ColorArcProgressBar_max_value, 60);
//        setCurrentValues(curValues);
        setMaxValues(maxValues);
        a.recycle();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = (int) (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE);
        int height= (int) (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE);
        setMeasuredDimension(width, height);
    }

    private void initView() {

        diameter = 3 * getScreenWidth() / 5;
        //弧形的矩阵区域
        bgRect = new RectF();
        bgRect.top = longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE;
        bgRect.left = longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE;
        bgRect.right = diameter + (longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE);
        bgRect.bottom = diameter + (longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE);


        oval = new RectF(longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE + progressWidth/2
                , longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE + progressWidth/2,
                diameter + (longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE) -progressWidth/2,
                diameter + (longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE) - progressWidth/2);//目的让字体显示出来

        //圆心
        centerX = (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE)/2;
        centerY = (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE)/2;

        //圆环半径
        radius = centerX - (longdegree + progressWidth/2 + DEGREE_PROGRESS_DISTANCE + progressWidth/2);



        //外部刻度线
        degreePaint = new Paint();
        degreePaint.setColor(Color.parseColor(longDegreeColor));

        //整个弧形
        allArcPaint = new Paint();
        allArcPaint.setAntiAlias(true);
        allArcPaint.setStyle(Paint.Style.STROKE);
        allArcPaint.setStrokeWidth(bgArcWidth);
        allArcPaint.setColor(Color.parseColor(bgArcColor));
        allArcPaint.setStrokeCap(Paint.Cap.ROUND);

        //当前进度的弧形
        progressPaint = new Paint();
        progressPaint.setAntiAlias(true);
        progressPaint.setStyle(Paint.Style.STROKE);
        progressPaint.setStrokeCap(Paint.Cap.ROUND);
        progressPaint.setStrokeWidth(progressWidth);
        progressPaint.setColor(Color.GREEN);

        //内容显示文字
        vTextPaint = new Paint();
        vTextPaint.setTextSize(textSize);
        vTextPaint.setColor(Color.BLACK);
        vTextPaint.setTextAlign(Paint.Align.CENTER);

        //指针数字显示
        vTextPaint_zhi = new Paint();
        vTextPaint_zhi.setTextSize(dipToPx(15));
        vTextPaint_zhi.setColor(Color.BLACK);
        vTextPaint_zhi.setTextAlign(Paint.Align.CENTER);


        //显示单位文字
        hintPaint = new Paint();
        hintPaint.setTextSize(hintSize);
        hintPaint.setColor(Color.parseColor(hintColor));
        hintPaint.setTextAlign(Paint.Align.CENTER);

        //显示标题文字
        curSpeedPaint = new Paint();
        curSpeedPaint.setTextSize(curSpeedSize);
        curSpeedPaint.setColor(Color.parseColor(hintColor));
        curSpeedPaint.setTextAlign(Paint.Align.CENTER);

        mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        sweepGradient = new SweepGradient(centerX, centerY, colors, null);
        rotateMatrix = new Matrix();

        //加载进度小圆点
        mThumbPress = getResources().getDrawable(R.drawable.btn_lamp_plate_down);// 圆点图片
        int  thumbHalfheight = mThumbPress.getIntrinsicHeight() / 2;
        int thumbHalfWidth = mThumbPress.getIntrinsicWidth() / 2;
        mThumbPress.setBounds(-thumbHalfWidth, -thumbHalfheight, thumbHalfWidth, thumbHalfheight);
        paddingOuterThumb = thumbHalfheight;//按下的白色图标
        minValidateTouchArcRadius = (int) (radius - paddingOuterThumb*1.5f);
        maxValidateTouchArcRadius = (int) (radius + paddingOuterThumb*1.5f);


    }

    @Override
    protected void onDraw(Canvas canvas) {
        //抗锯齿
        canvas.setDrawFilter(mDrawFilter);
        if (isNeedDial) {
            //画刻度线
            for (int i = 0; i < 40; i++) {
                if (i > 15 && i < 25) {
                    canvas.rotate(9, centerX, centerY);
                    continue;
                }
                if (i % 5 == 0) {//0,5,10,15,25,35,
                    degreePaint.setStrokeWidth(dipToPx(2));
                    switch (i) {
                        case 0: //45
                            degreePaint.setColor(Color.parseColor("#FE1303"));//                            canvas.drawText("150",
                                    centerX,centerY - diameter / 2 - progressWidth - DEGREE_PROGRESS_DISTANCE + progressWidth/2 ,   vTextPaint_zhi);
                            break;
                        case 5://90
                            degreePaint.setColor(Color.parseColor("#AB033D"));//红褐色
                            canvas.drawText("200",
                                    centerX,centerY - diameter / 2 - progressWidth - DEGREE_PROGRESS_DISTANCE + progressWidth/2 ,   vTextPaint_zhi);
                            break;
                        case 10://135
                            degreePaint.setColor(Color.parseColor("#450F6F"));//浅褐色
                            canvas.drawText("300",
                                    centerX,centerY - diameter / 2 - progressWidth - DEGREE_PROGRESS_DISTANCE + progressWidth/2 ,   vTextPaint_zhi);
                            break;
                        case 15://180
                            degreePaint.setColor(Color.parseColor("#450F6C"));//深褐色
                            canvas.drawText("500",
                                    centerX,centerY - diameter / 2 - progressWidth - DEGREE_PROGRESS_DISTANCE + progressWidth/2 ,   vTextPaint_zhi);
                            break;
                        case 25://225
                            degreePaint.setColor(Color.parseColor("#8BCD1E"));//绿
                            canvas.drawText("0",
                                    centerX,centerY - diameter / 2 - progressWidth - DEGREE_PROGRESS_DISTANCE + progressWidth/2 ,   vTextPaint_zhi);
                            break;
                        case 30://270
                            degreePaint.setColor(Color.parseColor("#E3DF1A"));//前黄绿
                            canvas.drawText("50",
                                    centerX,centerY - diameter / 2 - progressWidth - DEGREE_PROGRESS_DISTANCE + progressWidth/2 ,   vTextPaint_zhi);
                            break;
                        case 35://315
                            degreePaint.setColor(Color.parseColor("#ED870D"));//黄红
                            canvas.drawText("100",
                                    centerX,centerY - diameter / 2 - progressWidth - DEGREE_PROGRESS_DISTANCE + progressWidth/2 ,   vTextPaint_zhi);
                            break;
                    }
                    canvas.drawCircle(centerX,centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE +progressWidth/2
                    ,dipToPx(3),degreePaint);
                    //float cx, float cy, float radius, @NonNull Paint paint
                }
                canvas.rotate(9, centerX, centerY);//每隔,
            }
        }

        //整个弧
        canvas.drawArc(oval, startAngle, sweepAngle, false, allArcPaint);

        //设置渐变色
        rotateMatrix.setRotate(130, centerX, centerY);
        sweepGradient.setLocalMatrix(rotateMatrix);
        progressPaint.setShader(sweepGradient);

        //当前进度
        canvas.drawArc(oval, startAngle, currentAngle, false, progressPaint);

        if (isNeedContent) {
            canvas.drawText(String.format("%.0f", curValues), centerX, centerY + textSize / 3, vTextPaint);
        }
        if (isNeedUnit) {
            canvas.drawText(hintString, centerX, centerY + 2 * textSize / 3, hintPaint);
        }
        if (isNeedTitle) {
            canvas.drawText(titleString, centerX, centerY - 2 * textSize / 3, curSpeedPaint);
        }

        //画移动白点
        //paint.setStyle(Paint.Style.FILL_AND_STROKE);
        PointF progressPoint = ChartUtil.calcArcEndPointXY(centerX, centerY, radius, 360 * progress / maxValues, 270);
        //canvas.drawCircle(progressPoint.x, progressPoint.y, pointRadius, paint);
        // Thumb
        canvas.save();
        canvas.translate(progressPoint.x, progressPoint.y);
        mThumbPress.draw(canvas);
        canvas.restore();

        invalidate();

    }

    public static class ChartUtil {

        /**
         * 依圆心坐标,半径,扇形角度,计算出扇形终射线与圆弧交叉点的xy坐标
         * @param cirX
         * @param cirY
         * @param radius
         * @param cirAngle
         * @return
         */
        public static PointF calcArcEndPointXY(float cirX, float cirY, float radius, float cirAngle){//一个在270度那里,一个从270度开始叠加。
            //        //centerX, centerY, radius, 0, 270
            //cirAngle = (orginAngle + cirAngle) % 360;
            float posX = 0.0f;
            float posY = 0.0f;
            //将角度转换为弧度
            float arcAngle = (float) (Math.PI * cirAngle / 180.0);
            if (cirAngle < 90)
            {
                posX = cirX + (float)(Math.cos(arcAngle)) * radius;
                posY = cirY + (float)(Math.sin(arcAngle)) * radius;
            }
            else if (cirAngle == 90)
            {
                posX = cirX;
                posY = cirY + radius;
            }
            else if (cirAngle > 90 && cirAngle < 180)
            {
                arcAngle = (float) (Math.PI * (180 - cirAngle) / 180.0);
                posX = cirX - (float)(Math.cos(arcAngle)) * radius;
                posY = cirY + (float)(Math.sin(arcAngle)) * radius;
            }
            else if (cirAngle == 180)
            {
                posX = cirX - radius;
                posY = cirY;
            }
            else if (cirAngle > 180 && cirAngle < 270)
            {
                arcAngle = (float) (Math.PI * (cirAngle - 180) / 180.0);
                posX = cirX - (float)(Math.cos(arcAngle)) * radius;
                posY = cirY - (float)(Math.sin(arcAngle)) * radius;
            }
            else if (cirAngle == 270)
            {
                posX = cirX;
                posY = cirY - radius;
            }
            else
            {
                arcAngle = (float) (Math.PI * (360 - cirAngle) / 180.0);
                posX = cirX + (float)(Math.cos(arcAngle)) * radius;
                posY = cirY - (float)(Math.sin(arcAngle)) * radius;
            }
            return new PointF(posX, posY);     //new PointF();//   运动小点的位置坐标
        }

        public static PointF calcArcEndPointXY(float cirX, float cirY, float radius, float cirAngle, float orginAngle){
            //centerX, centerY, radius, 0, 270
            cirAngle = (orginAngle + cirAngle) % 360;
            return calcArcEndPointXY(cirX, cirY, radius, cirAngle);
        }
    }

    private boolean downOnArc = false;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                if (isTouchArc(x, y)) {
                    downOnArc = true;
                    updateArc(x, y);
                    return true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (downOnArc) {
                    updateArc(x, y);
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                downOnArc = false;
                invalidate();
//                if (changeListener != null) {
//                    changeListener.onProgressChangeEnd(max, progress);
//                }
                break;
        }
        return super.onTouchEvent(event);
    }

    // 根据点的位置,更新进度
    private void updateArc(int x, int y) {
        int cx = x - getWidth() / 2;
        int cy = y - getHeight() / 2;
        // 计算角度,得出(-1->1)之间的数据,等同于(-180°->180°        double angle = Math.atan2(cy, cx)/Math.PI;
        // 将角度转换成(0->2)之间的值,然后加上90°的偏移量
        angle = ((2 + angle)%2 + (90/180f))%2;
        // 用(0->2)之间的角度值乘以总进度,等于当前进度
        progress = (int) (angle * maxValues/2);
//        if (changeListener != null) {
//            changeListener.onProgressChange(max, progress);
//        }
        Log.e("robin debug","progress:" + progress);
        invalidate();
    }

    /**
     * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步
     * 刷新界面调用postInvalidate()能在非UI线程刷新
     * @param progress
     */
    public synchronized void setProgress(int progress) {
        if(progress < 0){
            throw new IllegalArgumentException("progress not less than 0");
        }
        if(progress > 498){//maxProgress
            progress = (int) 498;
        }
        if(progress <= 498){
            this.progress = progress;
            postInvalidate();
        }
    }



    private int minValidateTouchArcRadius; // 最小有效点击半径
    private int maxValidateTouchArcRadius; // 最大有效点击半径

    // 判断是否按在圆边上
    private boolean isTouchArc(int x, int y) {
        double d = getTouchRadius(x, y);
        if (d >= minValidateTouchArcRadius && d <= maxValidateTouchArcRadius) {
            return true;
        }
        return false;
    }

    // 计算某点到圆点的距离
    private double getTouchRadius(int x, int y) {
        int cx = x - getWidth() / 2;
        int cy = y - getHeight() / 2;
        return Math.hypot(cx, cy);
    }

    /**
     * 设置最大值
     * @param maxValues
     */
    public void setMaxValues(float maxValues) {
        this.maxValues = maxValues;
        k = sweepAngle/maxValues;
    }

    /**
     * 设置当前值
     * @param currentValues
     */
    public void setCurrentValues(float currentValues) {
        if (currentValues > maxValues) {
            currentValues = maxValues;
        }
        if (currentValues < 0) {
            currentValues = 0;
        }
        this.curValues = currentValues;
        lastAngle = currentAngle;
        setAnimation(lastAngle, currentValues * k, aniSpeed);
    }

    /**
     * 设置整个圆弧宽度
     * @param bgArcWidth
     */
    public void setBgArcWidth(int bgArcWidth) {
        this.bgArcWidth = bgArcWidth;
    }

    /**
     * 设置进度宽度
     * @param progressWidth
     */
    public void setProgressWidth(int progressWidth) {
        this.progressWidth = progressWidth;
    }

    /**
     * 设置速度文字大小
     * @param textSize
     */
    public void setTextSize(int textSize) {
        this.textSize = textSize;
    }

    /**
     * 设置单位文字大小
     * @param hintSize
     */
    public void setHintSize(int hintSize) {
        this.hintSize = hintSize;
    }

    /**
     * 设置单位文字
     * @param hintString
     */
    public void setUnit(String hintString) {
        this.hintString = hintString;
        invalidate();
    }

    /**
     * 设置直径大小
     * @param diameter
     */
    public void setDiameter(int diameter) {
        this.diameter = dipToPx(diameter);
    }

    /**
     * 设置标题
     * @param title
     */
    private void setTitle(String title){
        this.titleString = title;
    }

    /**
     * 设置是否显示标题
     * @param isNeedTitle
     */
    private void setIsNeedTitle(boolean isNeedTitle) {
        this.isNeedTitle = isNeedTitle;
    }

    /**
     * 设置是否显示单位文字
     * @param isNeedUnit
     */
    private void setIsNeedUnit(boolean isNeedUnit) {
        this.isNeedUnit = isNeedUnit;
    }

    /**
     * 设置是否显示外部刻度盘
     * @param isNeedDial
     */
    private void setIsNeedDial(boolean isNeedDial) {
        this.isNeedDial = isNeedDial;
    }

    /**
     * 为进度设置动画
     * @param last
     * @param current
     */
    private void setAnimation(float last, float current, int length) {
        progressAnimator = ValueAnimator.ofFloat(last, current);
        progressAnimator.setDuration(length);
        progressAnimator.setTarget(currentAngle);
        progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentAngle= (float) animation.getAnimatedValue();
                curValues = currentAngle/k;
            }
        });
        progressAnimator.start();
    }

    /**
     * dip 转换成px
     * @param dip
     * @return
     */
    private int dipToPx(float dip) {
        float density = getContext().getResources().getDisplayMetrics().density;
        return (int)(dip * density + 0.5f * (dip >= 0 ? 1 : -1));
    }

    /**
     * 得到屏幕宽度
     * @return
     */
    private int getScreenWidth() {
        WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.widthPixels;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值