android自定义可拖拽的仪表盘

Fern ·
更新时间:2024-09-21
· 1325 次阅读

本文实例为大家分享了android自定义可拖拽的仪表盘的具体代码,供大家参考,具体内容如下

因为项目最近需要用到仪表盘,又不想使用之前使用的背景图的方式。主要是想自己写一点代码。觉得绘制要比图片好。于是有了下面这张图:

面从弧度,刻度,文字,指针都是canvas绘制出来的。

/** * Created by xulc on 2018/7/18. */ public class DashboardView extends View { private int minWidthDP = 200; private int minHeightDP = 100; private Paint arcPaint,arcInnerPaint,linePaint,textPaint; private int arcColor = Color.parseColor("#0096ff"); //外层弧形颜色 private int arcInnerColor = Color.parseColor("#FFFFFFFF"); //内层弧形颜色 private int lineColor = Color.parseColor("#333333"); //线条颜色 private int pointerColor = Color.parseColor("#439AFF"); //指针颜色 private int arcWidthDP = 1; private RectF arcRectF,arcInnerRectF; private int widthDash = 0;//表盘的宽度 private int mwidth =0; private int mheight = 0; private float shortlineLength = 0 ,longlineLength = 0; //线的长度 private Path path = new Path(); private Path pointerPath = new Path(); //指针绘制路径 private Region pointerRegion = new Region(); //指针区域 private RectF rectF = new RectF(); private boolean isChoosePointer = false; private int mdegree = 0; public DashboardView(Context context) { this(context,null); } public DashboardView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initPaint(); } //初始化相关资源 private void initPaint() { arcPaint = new Paint(); arcPaint.setColor(arcColor); arcPaint.setAntiAlias(true); arcPaint.setStrokeCap(Paint.Cap.SQUARE); arcPaint.setStrokeWidth(1); arcPaint.setStyle(Paint.Style.FILL); arcInnerPaint = new Paint(); arcInnerPaint.setColor(arcInnerColor); arcInnerPaint.setAntiAlias(true); arcInnerPaint.setStrokeCap(Paint.Cap.SQUARE); arcInnerPaint.setStrokeWidth(1); arcInnerPaint.setStyle(Paint.Style.FILL); linePaint = new Paint(); linePaint.setColor(lineColor); linePaint.setAntiAlias(true); linePaint.setStrokeCap(Paint.Cap.SQUARE); linePaint.setStrokeWidth(arcWidthDP); linePaint.setStyle(Paint.Style.FILL); textPaint = new Paint(); textPaint.setColor(lineColor); textPaint.setAntiAlias(true); linePaint.setStrokeCap(Paint.Cap.SQUARE); linePaint.setStrokeWidth(arcWidthDP); linePaint.setStyle(Paint.Style.STROKE); textPaint.setTextAlign(Paint.Align.LEFT); textPaint.setTextSize(30); arcRectF = new RectF(); arcInnerRectF = new RectF(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); if(widthSize < DensityUtil.dip2px(getContext(),minWidthDP)||heightSize < DensityUtil.dip2px(getContext(),minHeightDP)){ widthSize = DensityUtil.dip2px(getContext(),minWidthDP); heightSize = DensityUtil.dip2px(getContext(),minHeightDP); } if(widthSize/2 != heightSize){ heightSize = widthSize/2; } setMeasuredDimension(widthSize,heightSize + 50); arcRectF.left = 0; arcRectF.bottom = heightSize*2; arcRectF.right = widthSize; arcRectF.top = 0; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); widthDash = DensityUtil.dip2px(getContext(),50); arcInnerRectF.left = widthDash; arcInnerRectF.bottom = arcRectF.bottom - widthDash; arcInnerRectF.right = arcRectF.bottom -widthDash; arcInnerRectF.top = widthDash; shortlineLength = widthDash/7; longlineLength = widthDash/5; mwidth = getWidth(); mheight = getHeight() - 50; Log.d("xulc","mheight----->"+mheight); Log.d("xulc","arcRectF.bottom----->"+arcRectF.bottom); } @Override protected void onDraw(Canvas canvas) { arcPaint.setColor(arcColor); canvas.drawArc(arcRectF,180,180,true,arcPaint); //绘制外弧形 canvas.drawArc(arcInnerRectF,180,180,true,arcInnerPaint); //绘制内部弧形 canvas.save(); drawScale(canvas); //绘制刻度 canvas.restore(); drawText(canvas); //绘制文本 drawPointer(canvas,mdegree); //绘制指针 } private int mradius = 50; //绘制指针 private void drawPointer(Canvas canvas,float degree){ pointerPath.reset(); if(isChoosePointer){ arcPaint.setColor(pointerColor); } pointerPath.reset(); pointerPath.moveTo((float)( mwidth/2 - mradius*Math.sin(degree/180f*Math.PI)),(float)( mheight + mradius*Math.cos(degree/180f*Math.PI))); //下切点 pointerPath.lineTo(mwidth/2 - (float) Math.cos(degree/180f*Math.PI)*(mheight - widthDash - longlineLength -mradius),mheight - (float) Math.sin(degree/180f*Math.PI)*(mheight - widthDash - longlineLength-mradius)); pointerPath.lineTo((float)( mwidth/2 + mradius*Math.sin(degree/180f*Math.PI)),(float)( mheight - mradius*Math.cos(degree/180f*Math.PI))); pointerPath.close(); pointerPath.computeBounds(rectF,true); pointerRegion.setPath(pointerPath,new Region((int) rectF.left,(int) rectF.top,(int) rectF.right,(int) rectF.bottom)); canvas.drawPath(pointerPath,arcPaint); //path转化为Region区域,方便判断用户点击的位置 path.reset(); arcPaint.setColor(arcColor); path.addCircle(mwidth/2,mheight,mradius, Path.Direction.CW); canvas.drawPath(path,arcPaint); textPaint.setTextAlign(Paint.Align.CENTER); canvas.drawText(""+mdegree,mwidth/2,mheight,textPaint); } //设置度数 public void setDegree(int degree){ if(0<=degree && degree<=180){ mdegree = degree; invalidate(); } } //触摸事件 @Override public boolean onTouchEvent(MotionEvent event) { float startx ,starty; if(event.getAction()==MotionEvent.ACTION_DOWN){ startx = event.getX(); starty = event.getY(); if(pointerRegion.contains((int) startx,(int) starty)){ //在其中 isChoosePointer =true; invalidate(); return true; //消费当前事件,否则不会继续分发后续事件 } return false; }else if(event.getAction()==MotionEvent.ACTION_MOVE){ if(isChoosePointer){ float x = event.getX(); float y = event.getY(); if(y <= mheight && x!=mwidth/2){ double degree= Math.atan2((mheight-y) ,(mwidth/2 - x)); setDegree((int) (degree/Math.PI*180)); }else{ if(y > mheight&& x < mwidth/2){ //说明滑到下面了 setDegree(0); }else if(y > mheight&& x > mwidth/2){ setDegree(180); } } return true; }else{ return false; } }else if(event.getAction()==MotionEvent.ACTION_UP||event.getAction()==MotionEvent.ACTION_CANCEL){ isChoosePointer =false; invalidate(); return true; } return super.onTouchEvent(event); } //绘制文字 private void drawText(Canvas canvas) { textPaint.setTextAlign(Paint.Align.LEFT); for(int i=0;i<=6;i++){ int degree = i*30; float textWidth = textPaint.measureText(""+degree); if(degree ==0){ canvas.drawText("" + degree,mwidth/2 - (float) Math.cos(degree/180f*Math.PI)*(mheight - widthDash - longlineLength -10) - textWidth/2,mheight - (float) Math.sin(degree/180f*Math.PI)*(mheight - widthDash - longlineLength-10)+7,textPaint); } //向右边移动7个像素 向下边移动7个像素 else if(degree == 30){ canvas.drawText("" + degree,mwidth/2 - (float) Math.cos(degree/180f*Math.PI)*(mheight - widthDash - longlineLength-10) - textWidth/2,mheight - (float) Math.sin(degree/180f*Math.PI)*(mheight - widthDash - longlineLength-10)+7 ,textPaint); }else if(degree ==60){ canvas.drawText("" + degree,mwidth/2 - (float) Math.cos(degree/180f*Math.PI)*(mheight - widthDash - longlineLength-10) - textWidth/2,mheight - (float) Math.sin(degree/180f*Math.PI)*(mheight - widthDash - longlineLength-10)+7 ,textPaint); }else if(degree ==90){ canvas.drawText("" + degree,mwidth/2 - (float) Math.cos(degree/180f*Math.PI)*(mheight - widthDash - longlineLength-10) - textWidth/2,mheight - (float) Math.sin(degree/180f*Math.PI)*(mheight - widthDash - longlineLength-10)+7 ,textPaint); }else{ canvas.drawText("" + degree,mwidth/2 - (float) Math.cos(degree/180f*Math.PI)*(mheight - widthDash - longlineLength - 10) - textWidth,mheight - (float) Math.sin(degree/180f*Math.PI)*(mheight - widthDash - longlineLength-10)+7 ,textPaint); } } } //绘制刻度 private void drawScale(Canvas canvas){ for(int i=0;i<=36;i++){ //180角度,30度一个长线 0 30 60 90 120 150 180 5条小线 5度一个小线 if(i%6==0){//长线 canvas.drawLine(widthDash,mheight,widthDash + longlineLength ,mheight,linePaint); }else{ //短线 canvas.drawLine(widthDash,mheight,widthDash + shortlineLength ,mheight,linePaint); } canvas.rotate(5,mwidth/2,mheight); } } }

整体代码差不多就这样,代码中详尽的注释。代码基本上都在这了,就不上传git了。



仪表盘 Android

需要 登录 后方可回复, 如果你还没有账号请 注册新账号