zoukankan      html  css  js  c++  java
  • 自定义仪表盘

    效果图

    package com.mdm.dashboard;
    
    import android.animation.ObjectAnimator;
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.graphics.PointF;
    import android.os.Build;
    import android.text.TextPaint;
    import android.util.AttributeSet;
    import android.util.TypedValue;
    import android.view.View;
    import android.widget.Toast;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import androidx.annotation.Nullable;
    import androidx.annotation.RequiresApi;
    
    public class DashBoardView extends View {
    
        private Context mContext;
        //刻度最大值
        private float maxValue = 100;
        //当前指针指的值
        private float currentValue = 33;
        //单位值代表了多少度
        private float cellAngle = 1;
    
        //半径
        private float radius = 100;
        //圆心坐标
        private PointF centerPoint;
        //边距
        private float margin = 5;
        //仪表盘宽度
        private float arcLineWidth = 20;
    
        private List<RangInfo> mRangList;
        private Paint dashBoardPaint;
        private Paint dashLinePaint;
        private Paint pointerPaint;
        //刻度文字
        private TextPaint dashLineTextPaint;
        //底部标题文字
        private TextPaint dashTitleTextPaint;
        private int titleColor;
        //标题
        private String title = "回报率";
        //单位
        private String unit = "%";
        private Path path;
        public DashBoardView(Context context) {
            super(context);
            init(context);
        }
    
        public DashBoardView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        public DashBoardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context);
        }
    
        /**
         * 初始化
         * @param context
         */
        private void init(Context context) {
            dashBoardPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            dashBoardPaint.setStyle(Paint.Style.STROKE);
            dashBoardPaint.setStrokeWidth(arcLineWidth);
    
            dashLineTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
            dashLineTextPaint.setStyle(Paint.Style.FILL);
            dashLineTextPaint.setStrokeWidth(2);
            dashLineTextPaint.setTextSize(sp2px(20));
    
            dashTitleTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
            dashTitleTextPaint.setStyle(Paint.Style.FILL);
            dashTitleTextPaint.setStrokeWidth(2);
            dashTitleTextPaint.setTextSize(sp2px(20));
    
            pointerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            pointerPaint.setStyle(Paint.Style.FILL);
    //        pointerPaint.setColor();
    
            dashLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            dashLinePaint.setStrokeWidth(2);
            dashLinePaint.setColor(Color.WHITE);
            dashLinePaint.setStrokeCap(Paint.Cap.ROUND);
    
            centerPoint = new PointF();
            path = new Path();
            mContext = context;
            setRanValue(new ArrayList<RangInfo>());
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int height = getMeasuredHeight();
            int width = getMeasuredWidth();
    
            if(height > width){
                margin = width / 20f;
                width -= (margin * 2) + arcLineWidth*2;
    //            radius = ((width / 6f)*5f)/2f;
                radius = width / 2f;
            }else{
                margin = height / 20f;
                height -= (margin * 2) + arcLineWidth*2;
    //            radius = ((height / 6f)*5f)/2f;
                radius = height/2f;
            }
            centerPoint.set(getMeasuredWidth()/2, getMeasuredHeight()/2);
        }
    
        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        @Override
        protected void onDraw(Canvas canvas) {
            drawDashBoard(canvas);
            drawLine(canvas);
            drawPointer(canvas);//画指针
            drawTitle(canvas);
        }
    
        /**
         * 绘制仪表盘
         * @param canvas
         */
        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        private void drawDashBoard(Canvas canvas){
            if(mRangList != null) {
                float startAngle = 135;
                for (RangInfo info : mRangList) {
                    dashBoardPaint.setColor(info.getColor());
                    //记录下仪表盘的颜色范围区间用于判断
                    PointF pointF = new PointF(startAngle - 135,(startAngle + info.getValue() * cellAngle)-135);
                    info.setPointF(pointF);
                    //画弧线
    //                canvas.drawArc(centerPoint.x - radius,margin + arcLineWidth,centerPoint.x + radius,margin + arcLineWidth + 2 * radius,startAngle,info.getValue() * cellAngle,false,dashBoardPaint);
                    canvas.drawArc(centerPoint.x - radius,centerPoint.y - radius,centerPoint.x + radius,centerPoint.y + radius,startAngle,info.getValue() * cellAngle,false,dashBoardPaint);
                    startAngle += info.getValue() * cellAngle;
                }
            }
        }
    
    
        /**
         * 画刻度
         * @param canvas
         */
        private void drawLine(Canvas canvas){
            canvas.save();
            canvas.translate(centerPoint.x,centerPoint.y);
            canvas.rotate(135);
            for (int i = 0; i <= 270;){
                if(i % 45 == 0){
                    drawLineText(canvas,i);
                    canvas.drawLine(radius - arcLineWidth*4/3,0,radius + arcLineWidth/2,0,dashLinePaint);
                }
                else canvas.drawLine(radius - arcLineWidth/2,0,radius + arcLineWidth/2,0,dashLinePaint);
                canvas.rotate(9);
                i+=9;
            }
            canvas.restore();
        }
    
        /**
         * 画刻度值
         */
        private void drawLineText(Canvas canvas,float angle){
            float value = angle / cellAngle;
            canvas.save();
            drawCenterText(value,angle,canvas);
            canvas.restore();
        }
    
        /**
         * 获取圆上的点的坐标
         * @return
         * 这里的圆心坐标为什么是0,0是因为canvas已经移到圆的圆心的位置,那么新的坐标轴中的圆心点就是0,0
         */
        private PointF getRoundXY(float angle,float radius){
            PointF xyPoint = new PointF();
            xyPoint.x = (float) (0 + radius * Math.cos(angle * Math.PI/180));
            xyPoint.y = (float) (0 + radius * Math.sin(angle * Math.PI/180));
            return xyPoint;
        }
    
        /**
         * 居中显示文字
         * @param value
         * @param canvas
         */
        private void drawCenterText( float value,float angle,Canvas canvas){
            TextPaint.FontMetrics fontMetrics = dashLineTextPaint.getFontMetrics();
            dashLineTextPaint.setTextAlign(Paint.Align.CENTER);
            int textBaseLine = (int) (0 + (fontMetrics.bottom - fontMetrics.top) /2 - fontMetrics.bottom);
    //        PointF pointF = getRoundXY(0,radius - arcLineWidth*2.5f);
            PointF pointF = getRoundXY(0, radius - arcLineWidth*4/3 - dashLineTextPaint.measureText(String.valueOf(Math.round(value)))/2);
            canvas.translate(pointF.x,pointF.y);
            canvas.rotate( -135-angle);
            dashLineTextPaint.setColor(getPointerTextColor(angle));
            canvas.drawText(String.valueOf(Math.round(value)), 0, textBaseLine, dashLineTextPaint);
    //        canvas.drawText(listener != null?listener.getFormatValue(value):String.valueOf(Math.round(value)), 0, textBaseLine, dashLineTextPaint);
        }
    
        /**
         * 画指针
         * @param canvas
         */
        private void drawPointer(Canvas canvas){
            pointerPaint.setColor(getPointerTextColor(currentValue *cellAngle));
            canvas.drawCircle(centerPoint.x,centerPoint.y,3,pointerPaint);
            canvas.save();
            canvas.translate(centerPoint.x,centerPoint.y);
            canvas.rotate(135 + currentValue *cellAngle);
            path.reset();
            path.moveTo(0,0);
            path.lineTo(radius * 1/10,-radius * 1/15);
            path.lineTo(radius * 3/4,0);
            path.lineTo(radius * 1/10,radius * 1/15);
            path.close();
            canvas.drawPath(path,pointerPaint);
            canvas.restore();
        }
    
        /**
         * 画title
         * @param canvas
         */
        private void drawTitle(Canvas canvas){
            if(titleColor != 0) dashTitleTextPaint.setColor(titleColor);
            TextPaint.FontMetrics fm = dashTitleTextPaint.getFontMetrics();
            float textHeight  = fm.bottom - fm.top;
            dashTitleTextPaint.setTextAlign(Paint.Align.CENTER);
            canvas.drawText(title, centerPoint.x, centerPoint.y + radius * 4/5 + textHeight, dashTitleTextPaint);
            dashTitleTextPaint.setColor(getPointerTextColor(currentValue * cellAngle));
            canvas.drawText((listener != null?listener.getFormatValue(currentValue):Math.round(currentValue)) + unit, centerPoint.x, centerPoint.y + radius * 4/5, dashTitleTextPaint);
        }
    
        /**
         * 指针和文字的颜色
         * @param angle 度数 减去135后的度数
         * @return 获取某个区域的文字的颜色和指针的颜色
         */
        private int getPointerTextColor(float angle){
            for (RangInfo info : mRangList){
                if(angle >= info.getPointF().x  && angle <= info.getPointF().y){
                    return info.getColor();
                }
            }
            return 0xff000000;
        }
    
        /**
         * 设置底部标题文字
         * @param title
         * @param unit
         * @return
         */
        public DashBoardView setTitle(String title, String unit){
            if(title == null) title = "";
            if(unit == null) unit = "";
            this.title = title;
            this.unit = unit;
            postInvalidate();
            return this;
        }
    
        /**
         * 设置title文字大小
         * @return
         */
        public DashBoardView setTitleSize(float textSize){
            if(textSize <= 0) textSize = 15;
            dashTitleTextPaint.setTextSize(sp2px(textSize));
            postInvalidate();
            return this;
        }
    
    
        /**
         * 设置title颜色
         * @param textColor
         * @return
         */
        public DashBoardView setTitleColor(int textColor){
            try{
                dashTitleTextPaint.setColor(textColor);
            }catch (Exception e){
                textColor = 0xff000000;
                dashTitleTextPaint.setColor(textColor);
            }
            titleColor = textColor;
            postInvalidate();
            return this;
        }
    
        /**
         * 设置区间值和颜色
         * @param rangInfos
         * @return
         */
        public DashBoardView setRanValue(List<RangInfo> rangInfos){
            if(rangInfos == null || rangInfos.size() == 0){
                mRangList = getDefaultRangList();
                return this;
            }
            float sum = 0;
            for(RangInfo info : rangInfos){
                if(info == null)continue;
                sum += info.getValue() < 0?0:info.getValue();
            }
            if(sum > 0){
                maxValue = sum;
                mRangList = rangInfos;
                cellAngle = 270 / maxValue;
            }else{
                mRangList = getDefaultRangList();
            }
            postInvalidate();
            return this;
        }
    
        /**
         * 便捷设置
         * @param ranValues
         * @return
         */
        public DashBoardView setRanValue(RangInfo... ranValues){
            if(ranValues == null || ranValues.length == 0)return this;
            List<RangInfo> rangInfos = new ArrayList<>();
            for (RangInfo rangInfo : ranValues){
                rangInfos.add(rangInfo);
            }
            setRanValue(rangInfos);
            return this;
        }
    
        /**
         * 获取当前指向的值
         * @return
         */
        public float getCurrentValue() {
            return currentValue;
        }
    
        /**
         * 用来做动画的设置当前指向的值
         * @param currentValue
         */
        private void setCurrentValue(float currentValue) {
            this.currentValue = currentValue;
            postInvalidate();
        }
    
        /**
         * 设置当前值
         * @param value
         * @param isAnim true 需要动画 false 不要动画
         */
        public void setValue(float value,boolean isAnim,IValueFormat listener){
            if(value < 0 || value > maxValue){
                Toast.makeText(mContext,"设置无效!设置的值大于当前最大值",Toast.LENGTH_LONG).show();
                return;
            }
            if(isAnim) ObjectAnimator.ofFloat(this,"currentValue",0,value).setDuration(2000).start();
            else setCurrentValue(value);
            setListener(listener);
        }
    
        /**
         * 设置当前值
         * @param value
         * @param isAnim true 需要动画 false 不要动画
         */
        public void setValue(float value,boolean isAnim){
            setValue(value,isAnim,null);
        }
    
        /**
         * 设置刻度线的颜色
         * @param lineColor
         */
        public DashBoardView setLineColor(int lineColor){
            if(dashLinePaint != null) {
                try {
                    dashLinePaint.setColor(lineColor);
                }catch (Exception e){
                    dashLinePaint.setColor(Color.WHITE);
                }
            }
            postInvalidate();
            return this;
        }
        /**
         * 设置刻度线的宽度
         * @param lineWidth
         */
        public DashBoardView setLineWidth(float lineWidth){
            if(lineWidth < 0)return this;
            dashLinePaint.setStrokeWidth(lineWidth);
            postInvalidate();
            return this;
        }
    
        /**
         * 设置刻度的文字大小
         */
        public DashBoardView setLineTextSize(float textSize){
            if(textSize < 0)return this;
            dashLineTextPaint.setTextSize(sp2px(textSize));
            postInvalidate();
            return this;
        }
    
        /**
         * 设置底部标题的文字大小
         * @param textSize
         * @return
         */
        public DashBoardView setTitleTextSize(float textSize){
            if(textSize < 0)return this;
            dashTitleTextPaint.setTextSize(sp2px(textSize));
            postInvalidate();
            return this;
        }
    
        /**
         * 设置圆环的线宽度
         * @param circleLineWidth
         * @return
         */
        public DashBoardView setDashBoardCircleLineWidth(float circleLineWidth){
            if(circleLineWidth < 0)return this;
            arcLineWidth = circleLineWidth;
            dashBoardPaint.setStrokeWidth(arcLineWidth);
            postInvalidate();
            return this;
        }
    
        /**
         * 获取默认的区间显示和总数
         * @return
         */
        private List<RangInfo> getDefaultRangList(){
            return getDefaultRangList(100f);
        }
    
        public List<RangInfo> getDefaultRangList(float maxValue){
            this.maxValue = maxValue;
            cellAngle = 270 / this.maxValue;
            List<RangInfo> list = new ArrayList<>();
            for (int i = 0;i < 4;i++){
                RangInfo info = new RangInfo();
                if(i == 0)info.setColor(0xffE13020);
                else if(i == 1) info.setColor(0xffD7A52D);
                else if(i == 2) info.setColor(0xff4089D7);
                else info.setColor(0xff30AD37);
                info.setValue(this.maxValue/4);
                list.add(info);
            }
            return list;
        }
    
    
        /**
         * dp转px
         * @param dpVal
         * @return
         */
        protected float dp2px(float dpVal) {
            return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics());
        }
    
        /**
         * sp转px
         * @param spVal
         * @return
         */
        protected float sp2px(float spVal) {
            return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, getResources().getDisplayMetrics());
        }
    
        /**
         * 设置区间范围
         */
        public static class RangInfo{
            private float value;
            private int color;
            //记录颜色角度的区间并不是坐标
            private PointF pointF;
            public RangInfo() {}
            public RangInfo(float value, int color) {
                this.value = value;
                this.color = color;
            }
    
            public float getValue() {
                return value;
            }
    
            public void setValue(float value) {
                this.value = value;
            }
    
            public int getColor() {
                return color;
            }
    
            public void setColor(int color) {
                this.color = color;
            }
    
            public PointF getPointF() {
                return pointF;
            }
    
            public void setPointF(PointF pointF) {
                this.pointF = pointF;
            }
        }
    
        /**
         * 取值处理
         */
        public interface IValueFormat{
            String getFormatValue(float value);
        }
    
        private IValueFormat listener;
        public DashBoardView setListener(IValueFormat listener){
            this.listener = listener;
            return this;
        }
    }

    使用方法:

    final DashBoardView dashBoardView = findViewById(R.id.dashBoard);
            findViewById(R.id.btnTest).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dashBoardView.setRanValue(dashBoardView.getDefaultRangList(250f))
                            .setLineTextSize(10)
                            .setLineWidth(1f)
                            .setDashBoardCircleLineWidth(5)
                            .setTitleColor(Color.WHITE)
                            .setTitleSize(10)
                            .setTitle("装逼率","%")
                            .setValue(100f, true, new DashBoardView.IValueFormat() {
                                @Override
                                public String getFormatValue(float value) {
                                    DecimalFormat df=new DecimalFormat("0.0");
                                    return df.format(value);
                                }
                            });
                }
            });
  • 相关阅读:
    IOS 开发者账号 (team账号)
    我能否把一个开发者帐号下的app转移到另一个开发者帐号下面?
    Xcode清楚缓存、清理多余证书
    CABasiAnimation的变化属性
    CATransform3DMakeRotation注意
    绘图详解(转摘)
    iOS开发UI篇—核心动画(UIView封装动画)(转摘)
    iOS开发UI篇—核心动画(转场动画和组动画)(转摘)
    iOS开发UI篇—核心动画(关键帧动画)(转摘)
    iOS开发UI篇—核心动画(基础动画)
  • 原文地址:https://www.cnblogs.com/woaixingxing/p/11937437.html
Copyright © 2011-2022 走看看