android自定義可拖拽的儀表盤
本文實(shí)例為大家分享了android自定義可拖拽的儀表盤的具體代碼,供大家參考,具體內(nèi)容如下
因?yàn)轫?xiàng)目最近需要用到儀表盤,又不想使用之前使用的背景圖的方式。主要是想自己寫一點(diǎn)代碼。覺得繪制要比圖片好。于是有了下面這張圖:
面從弧度,刻度,文字,指針都是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"); //內(nèi)層弧形顏色 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(); //指針區(qū)域 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(); } //初始化相關(guān)資源 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); //繪制內(nèi)部弧形 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))); //下切點(diǎn) 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轉(zhuǎn)化為Region區(qū)域,方便判斷用戶點(diǎn)擊的位置 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); } //設(shè)置度數(shù) 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; //消費(fèi)當(dāng)前事件,否則不會(huì)繼續(xù)分發(fā)后續(xù)事件 } 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); } //向右邊移動(dòng)7個(gè)像素 向下邊移動(dòng)7個(gè)像素 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度一個(gè)長線 0 30 60 90 120 150 180 5條小線 5度一個(gè)小線 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了。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解用RxJava實(shí)現(xiàn)事件總線(Event Bus)
本篇文章主要介紹了用RxJava實(shí)現(xiàn)事件總線(Event Bus),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11Android實(shí)現(xiàn)數(shù)據(jù)按照時(shí)間排序
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)數(shù)據(jù)按照時(shí)間排序的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09Android實(shí)現(xiàn)背景顏色滑動(dòng)漸變效果的全過程
在Android開發(fā)中,經(jīng)常需要設(shè)置控件的背景顏色或者圖片的src顏色,下面這篇文章主要給大家介紹了關(guān)于Android實(shí)現(xiàn)背景顏色滑動(dòng)漸變效果的相關(guān)資料,本文通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09ContentProvider客戶端處理provider邏輯分析
這篇文章主要為大家介紹了ContentProvider客戶端處理provider邏輯分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Android 中 requestWindowFeature()的應(yīng)用
本文主要介紹 Android requestWindowFeature()方法,這里對(duì) requestWindowFeature()方法進(jìn)行詳解,對(duì)應(yīng)用程序窗體顯示狀態(tài)的操作有進(jìn)一步了解,希望能幫助有需要的小伙伴2016-07-07android通過代碼的形式來實(shí)現(xiàn)應(yīng)用程序的方法
因?yàn)閼?yīng)用程序的安裝與卸載模塊在android系統(tǒng)中已經(jīng)寫好了,所以我們只需要激活就行了2013-10-10Android開發(fā)筆記 今天學(xué)到的一些屬性
離開實(shí)驗(yàn)室之前再貼上今天下午自己學(xué)到的一些基礎(chǔ)知識(shí) 上午干嘛了呢,忙著數(shù)據(jù)恢復(fù)呢2012-11-11