android自定義可拖拽的儀表盤
本文實例為大家分享了android自定義可拖拽的儀表盤的具體代碼,供大家參考,具體內(nèi)容如下
因為項目最近需要用到儀表盤,又不想使用之前使用的背景圖的方式。主要是想自己寫一點代碼。覺得繪制要比圖片好。于是有了下面這張圖:

面從弧度,刻度,文字,指針都是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))); //下切點
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ū)域,方便判斷用戶點擊的位置
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; //消費當(dāng)前事件,否則不會繼續(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);
} //向右邊移動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了。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
android 關(guān)于利用簽名的SHA1進行安全校驗的方法之一(推薦)
下面小編就為大家?guī)硪黄猘ndroid 關(guān)于利用簽名的SHA1進行安全校驗的方法之一(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01
安卓開發(fā)之FragmentPagerAdapter和FragmentStatePagerAdapter詳解
這篇文章主要介紹了安卓開發(fā)之FragmentPagerAdapter和FragmentStatePagerAdapter詳解的相關(guān)資料,需要的朋友可以參考下2022-08-08
Android中可以作為Log開關(guān)的一些操作及安全性詳解
Android的調(diào)試好伙伴Log在調(diào)試時非常有用,基本可以看Log而無需單點調(diào)試,尤其對實時大數(shù)據(jù)量的設(shè)備調(diào)試尤其有效,下面這篇文章就來給大家詳細介紹關(guān)于Android中可以作為Log開關(guān)的一些操作及安全性的相關(guān)資料,需要的朋友可以參考下。2017-12-12
Android 實現(xiàn)獲取手機里面的所有圖片詳解及實例
這篇文章主要介紹了Android 實現(xiàn)獲取手機里面的所有圖片詳解及實例的相關(guān)資料,需要的朋友可以參考下2017-05-05
Android自定義View 使用PathMeasure簡單模仿系統(tǒng)ProgressBar(四)
這篇文章主要為大家詳細介紹了Android自定義View,使用PathMeasure簡單模仿系統(tǒng)ProgressBar,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03
Android開發(fā)中l(wèi)ibs和jinLibs文件夾的作用詳解
這篇文章主要給大家介紹了關(guān)于Android開發(fā)中l(wèi)ibs和jinLibs文件夾的作用的相關(guān)資料,文中通過圖文及示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2017-09-09
Android實現(xiàn)Service在前臺運行服務(wù)
這篇文章主要為大家詳細介紹了Android中實現(xiàn)Service在前臺運行服務(wù),具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11

