亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Android自定義View實現漸變色儀表盤

2019-10-21 21:34:56
字體:
來源:轉載
供稿:網友

前言:最近一直在學自定義View的相關知識,感覺這在Android中還是挺難的一塊,當然這也是每個程序員必經之路,正好公司項目要求實現類似儀表盤的效果用于直觀的顯示公司數據,于是就簡單的寫了個demo,記錄實現的過程。上篇《Android自定義View實現圓弧進度效果》簡單記錄了圓弧及文字的繪制,漸變色的儀表盤效果將更加升入的介紹canvas及paint的使用(如畫布旋轉,paint的漸變色設置等)。

知識梳理

1.圓弧漸變色(SweepGradient)

2.圓弧上刻度繪制

3.指針指示當前數據位置(Bitmap)

4.數據文本跟隨弧度顯示(drawTextOnPath)

效果圖:

Android,View,漸變色,儀表盤

1.繼承自View

(1)重寫構造方法,初始化Paint

public DashBoardView(Context context) { this(context, null);}public DashBoardView(Context context, AttributeSet attrs) { this(context, attrs, 0);}public DashBoardView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init();}

初始化相關Paint

/** * 初始化Paint */private void init() { //設置默認寬高值 defaultSize = dp2px(260); //設置圖片線條的抗鋸齒 mPaintFlagsDrawFilter = new PaintFlagsDrawFilter   (0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); //最外層圓環漸變畫筆設置 mOuterGradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //設置圓環漸變色渲染 mOuterGradientPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); float position[] = {0.1f, 0.3f, 0.8f}; Shader mShader = new SweepGradient(width / 2, radius, mColors, position); mOuterGradientPaint.setShader(mShader); mOuterGradientPaint.setStrokeCap(Paint.Cap.ROUND); mOuterGradientPaint.setStyle(Paint.Style.STROKE); mOuterGradientPaint.setStrokeWidth(30); //最外層圓環刻度畫筆設置 mCalibrationPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mCalibrationPaint.setColor(Color.WHITE); mCalibrationPaint.setStyle(Paint.Style.STROKE); //中間圓環畫筆設置 mMiddlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mMiddlePaint.setStyle(Paint.Style.STROKE); mMiddlePaint.setStrokeCap(Paint.Cap.ROUND); mMiddlePaint.setStrokeWidth(5); mMiddlePaint.setColor(GRAY_COLOR); //內層圓環畫筆設置 mInnerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mInnerPaint.setStyle(Paint.Style.STROKE); mInnerPaint.setStrokeCap(Paint.Cap.ROUND); mInnerPaint.setStrokeWidth(4); mInnerPaint.setColor(GRAY_COLOR); PathEffect mPathEffect = new DashPathEffect(new float[]{5, 5, 5, 5}, 1); mInnerPaint.setPathEffect(mPathEffect); //外層圓環文本畫筆設置 mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTextPaint.setColor(GRAY_COLOR); mTextPaint.setTextSize(dp2px(12)); //中間文字畫筆設置 mCenterTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mCenterTextPaint.setTextAlign(Paint.Align.CENTER); //中間圓環進度畫筆設置 mMiddleProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mMiddleProgressPaint.setColor(GREEN_COLOR); mMiddleProgressPaint.setStrokeCap(Paint.Cap.ROUND); mMiddleProgressPaint.setStrokeWidth(5); mMiddleProgressPaint.setStyle(Paint.Style.STROKE); //指針圖片畫筆 mPointerBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPointerBitmapPaint.setColor(GREEN_COLOR); //獲取指針圖片及寬高 mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.pointer); mBitmapHeight = mBitmap.getHeight(); mBitmapWidth = mBitmap.getWidth();}

注:

A、最外層圓弧的漸變色使用的是SweepGradient類實現的,SweepGradient繼承自Shader;

B、注意漸變色的開始角度問題,如果跟圓弧起始角度不一致,記得使用矩陣轉換進行旋轉,再讓paint去設置shader;

C、SweepGradient的第3個參數int[] colors必須包含兩個及以上顏色值,不然會報錯;

D、SweepGradient的第四個參數的數組大小必須和第三個參數的數組大小一樣,也可以填入null。

(2)重寫onMeasure,用于測量view寬高

onMeasure方法:

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(remeasure(widthMeasureSpec, defaultSize),   remeasure(heightMeasureSpec, defaultSize));}

remeasure方法:

/** * 根據傳入的值進行重新測量 */public int remeasure(int measureSpec, int defaultSize) { int result; int specSize = MeasureSpec.getSize(measureSpec); switch (MeasureSpec.getMode(measureSpec)) {  case MeasureSpec.UNSPECIFIED:   //未指定   result = defaultSize;   break;  case MeasureSpec.AT_MOST:   //設置warp_content時設置默認值   result = Math.min(specSize, defaultSize);   break;  case MeasureSpec.EXACTLY:   //設置math_parent 和設置了固定寬高值   result=specSize;   break;  default:   result = defaultSize; } return result;}

(3)重寫onChange,用于獲取view寬高

在onChange方法中獲取當前View的寬高及獲取圓弧的半徑,初始化圓弧的RectF等

@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //確定View寬高 width = w; height = h; //圓環半徑 radius = width / 2; //外層圓環 float oval1 = radius - mOuterGradientPaint.getStrokeWidth() * 0.5f; mOuterRectF = new RectF(-oval1, -oval1, oval1, oval1); //中間和內層圓環 float oval2 = radius * 5 / 8; float oval3 = radius * 3 / 4; mInnerRectF = new RectF(-oval2 + dp2px(5), -oval2 + dp2px(5), oval2 - dp2px(5), oval2 - dp2px(5)); mMiddleRectF = new RectF(-oval3 + dp2px(10), -oval3 + dp2px(10), oval3 - dp2px(10), oval3 - dp2px(10)); //中間進度圓環 oval4 = radius * 6 / 8; mMiddleProgressRectF = new RectF(-oval4+ dp2px(10), -oval4+ dp2px(10), oval4- dp2px(10), oval4- dp2px(10));}

(4)重寫onDraw方法,用于繪制view

@SuppressLint("DrawAllocation")@Overrideprotected void onDraw(Canvas canvas) { //設置畫布繪圖無鋸齒 canvas.setDrawFilter(mPaintFlagsDrawFilter); //繪制圓弧 drawArc(canvas); //繪制圓弧上的刻度 drawCalibration(canvas); //繪制跟隨圓弧path的文字 drawArcText(canvas); //繪制圓弧中心文字 drawCenterText(canvas); //繪制當前bitmap指針指示進度 drawBitmapProgress(canvas);}

2.Canvas繪制view

mStartAngle=105f,mEndAngle=250f

(1)繪制圓弧

/** * 分別繪制外層 中間 內層圓環 */private void drawArc(Canvas canvas) { canvas.save(); canvas.translate(width / 2, height / 2); //畫布旋轉140° canvas.rotate(140); //最外層的漸變圓環 canvas.drawArc(mOuterRectF, -mStartAngle, -mEndAngle, false, mOuterGradientPaint); //繪制內層虛線圓弧 canvas.drawArc(mInnerRectF, -mStartAngle, -mEndAngle, false, mInnerPaint); //繪制中間圓弧 canvas.drawArc(mMiddleRectF, -mStartAngle, -mEndAngle, false, mMiddlePaint); canvas.restore();}

(2)繪制漸變色圓弧上的大小刻度

/** * 繪制外層漸變色圓弧上的大小刻度線 */private void drawCalibration(Canvas canvas) { int dst = (int) (2 * radius - mOuterGradientPaint.getStrokeWidth()); for (int i = 0; i <= 40; i++) {  canvas.save();  canvas.rotate(-(-30 + 6 * i), radius, radius);  if (i % 10 == 0) {   mCalibrationPaint.setStrokeWidth(4);   //繪制大刻度   canvas.drawLine(dst, radius, 2 * radius, radius, mCalibrationPaint);  } else {   //小刻度   mCalibrationPaint.setStrokeWidth(1);   canvas.drawLine(dst, radius, 2 * radius, radius, mCalibrationPaint);  }  canvas.restore(); }}

注:

A、圓弧的總弧度為240f,循環40次

B、小刻度每次旋轉6弧度,每繪制10次小刻度就會繪制一次大刻度,即大刻度每次旋轉60弧度

(3)繪制跟隨圓弧弧度描述文字

/** * 繪制跟隨圓弧弧度的文本 */private void drawArcText(Canvas canvas) { canvas.save(); //每次旋轉角度 int rotateAngle = 30; //旋轉畫布 canvas.rotate(-118, radius - dp2px(26), radius-dp2px(103)); for (int i = 0; i < valueList.size(); i++) {  //計算起始角度  int startAngle = 30 * i - 108;  //設置數據跟著圓弧繪制  Path paths = new Path();  paths.addArc(mInnerRectF, startAngle, rotateAngle);  float textLen = mTextPaint.measureText(valueList.get(i));  canvas.drawTextOnPath(valueList.get(i), paths, -textLen / 2 + dp2px(20), -dp2px(22), mTextPaint);  //canvas.drawText(text[i], radius - 10, radius * 3 / 16+dp2px(10), mTextPaint); } canvas.restore();}

注:

A、drawTextOnPath為文字隨path路徑顯示,drawTextOnPath的第3個參數hOffset為文字水平方向的偏移量,第4個參數vOffset為文字垂直方向的偏移量;

B、重點是畫布開始時的旋轉角度及不同文字的起始角度

(4)繪制圓弧中心的數據及描述信息

/** * 繪制圓弧中間的文本內容 */private void drawCenterText(Canvas canvas) { //繪制當前數據值 mCenterTextPaint.setColor(GREEN_COLOR); mCenterTextPaint.setTextSize(dp2px(25)); mCenterTextPaint.setStyle(Paint.Style.STROKE); canvas.drawText(String.valueOf(mAnimatorValue), radius, radius, mCenterTextPaint); //繪制當前數據描述 mCenterTextPaint.setTextSize(dp2px(20)); canvas.drawText(mCurrentDes, radius, radius + dp2px(25), mCenterTextPaint);}

(5)繪制當前數值對應的圓弧及指針圖片指示

/** * 繪制當前進度和指示圖片 */private void drawBitmapProgress(Canvas canvas) { //如果當前角度為0,則不繪制指示圖片 if (mCurrentAngle==0f){  return; } canvas.save(); canvas.translate(radius, radius); canvas.rotate(270); //繪制對應的圓弧 canvas.drawArc(mMiddleProgressRectF, -mStartAngle-20, mCurrentAngle+5, false, mMiddleProgressPaint); canvas.rotate(60 + mCurrentAngle); //利用矩陣平移使圖片指針方向始終指向刻度 Matrix matrix = new Matrix(); matrix.preTranslate(-oval4 - mBitmapWidth * 3 / 8 + 10, -mBitmapHeight / 2); canvas.drawBitmap(mBitmap, matrix, mPointerBitmapPaint); canvas.restore();}

注:為了使指針圖片的指針一直指向刻度盤上的刻度,這里使用了矩陣的平移。

3.添加動畫及數據

(1)動畫效果

/** * 當前數據對應弧度旋轉及當前數據自增動畫 */public void startRotateAnim() { ValueAnimator mAngleAnim = ValueAnimator.ofFloat(mCurrentAngle, mTotalAngle); mAngleAnim.setInterpolator(new AccelerateDecelerateInterpolator()); mAngleAnim.setDuration(2500); mAngleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  @Override  public void onAnimationUpdate(ValueAnimator valueAnimator) {   mCurrentAngle = (float) valueAnimator.getAnimatedValue();   postInvalidate();  } }); mAngleAnim.start(); ValueAnimator mNumAnim = ValueAnimator.ofInt(mAnimatorValue, mCurrentValue); mNumAnim.setDuration(2500); mNumAnim.setInterpolator(new LinearInterpolator()); mNumAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  @Override  public void onAnimationUpdate(ValueAnimator valueAnimator) {   mAnimatorValue = (int) valueAnimator.getAnimatedValue();   postInvalidate();  } }); mNumAnim.start();}

(2)設置數據及描述信息

/** * 設置數據 */public void setValues(int values, List<String> valueList) { this.valueList=valueList; if (values <= 0) {  mCurrentValue = values;  mTotalAngle = 0f;  mCurrentDes = ""; } else if (values <= 14000) {  mCurrentValue = values;  mTotalAngle = values / 14000f * 60-2;  Log.e("rcw","mTotalAngle="+mTotalAngle);  mCurrentDes = "基礎目標"; } else if (values>14000&&values <= 17000) {  mCurrentValue = values;  mCurrentDes = "測試目標";  mTotalAngle = values / 17000f * 120-2; } else if (values>17000&&values <= 21000) {  mCurrentValue = values;  mTotalAngle = values / 21000f * 180-2;  mCurrentDes = "保底目標"; } else {  mCurrentValue=values;  float ratio=values / 21000f;  if (ratio<20){   mTotalAngle = ratio+180;  }else {   mTotalAngle = (float) (ratio*0.2+200);  }  mCurrentDes = "沖刺目標"; } startRotateAnim();}

總結:自定義View實現儀表盤效果用到了canvas的旋轉及矩陣平移;drawTextOnpath使的文字跟隨path繪制;SweepGradient實現圓弧的漸變色效果。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久99热精品这里久久精品| 美女性感视频久久久| 欧美日韩一二三四五区| 2019日本中文字幕| 亚洲情综合五月天| 91丨九色丨国产在线| 日韩av影视在线| 欧美成人免费在线观看| 国产成人精品午夜| 欧美性猛交xxxxx水多| 中文字幕亚洲欧美日韩在线不卡| 91精品国产自产在线观看永久| 亚洲日本中文字幕| 日韩一区二区三区xxxx| 久久夜色撩人精品| 国产精品福利无圣光在线一区| 成人h视频在线| 国产日韩欧美一二三区| 免费91麻豆精品国产自产在线观看| 亚洲欧美成人在线| 国产精品色午夜在线观看| 九色精品免费永久在线| 亚洲精品美女网站| 中文字幕最新精品| 精品偷拍一区二区三区在线看| 精品福利免费观看| 51视频国产精品一区二区| 中日韩美女免费视频网址在线观看| 欧美高清一级大片| 国产精品中文久久久久久久| 亚洲精品久久久久中文字幕欢迎你| 欧美中在线观看| 欧美视频国产精品| 日韩电影大片中文字幕| 国产精品丝袜白浆摸在线| 亚洲老头同性xxxxx| 国产精品美女www爽爽爽视频| 亚洲视频网站在线观看| 亚洲欧美日韩一区二区三区在线| 亚洲精品国产精品自产a区红杏吧| 久久久久久久久亚洲| 69av成年福利视频| 中文亚洲视频在线| 最近的2019中文字幕免费一页| 国产成人av网| 91精品国产综合久久香蕉最新版| 中文字幕av一区| 欧美性猛交xxxx免费看漫画| 中国china体内裑精亚洲片| 97超碰国产精品女人人人爽| 日韩网站免费观看| 日韩免费视频在线观看| 亚洲www永久成人夜色| 亚洲精品720p| 日韩美女视频免费看| 麻豆国产精品va在线观看不卡| 永久免费看mv网站入口亚洲| 色樱桃影院亚洲精品影院| 98精品国产自产在线观看| 亚洲国产成人久久综合一区| 91精品国产高清久久久久久| 国产视频在线一区二区| 欧美最猛黑人xxxx黑人猛叫黄| 欧美电影在线观看完整版| 国产精品美女999| 欧美精品videossex性护士| 黑丝美女久久久| 久久精彩免费视频| 国产精品综合久久久| 亚洲一区久久久| 欧美午夜激情视频| 国产日韩欧美日韩大片| 久久久www成人免费精品张筱雨| 亚洲欧美日韩天堂一区二区| 亚洲自拍av在线| 国产在线拍揄自揄视频不卡99| 国产一区二区三区久久精品| 亚洲欧美日韩国产成人| 久久精品电影网站| 国产精品视频免费在线| 亚洲国产精品va在看黑人| 国产性猛交xxxx免费看久久| 在线观看视频亚洲| 91国产中文字幕| 欧美成人激情视频免费观看| 8090理伦午夜在线电影| 丝袜美腿亚洲一区二区| 久久久精品电影| 91丨九色丨国产在线| 亚洲国内精品视频| 91热福利电影| 国产精品直播网红| 亚洲精品在线视频| 在线播放亚洲激情| 久久久久久伊人| 亚洲视频在线观看网站| 北条麻妃一区二区在线观看| 国产日韩专区在线| 国产成人自拍视频在线观看| 91久久夜色精品国产网站| 91av在线免费观看| 日韩精品免费在线| 欧美日韩国产第一页| 97在线日本国产| 亚洲欧美国产精品va在线观看| 国产精品白嫩美女在线观看| 欧美日韩国产成人在线| 亚洲欧美在线看| 欧美激情视频在线免费观看 欧美视频免费一| 亚洲成av人片在线观看香蕉| 成人黄色免费网站在线观看| 日韩a**中文字幕| 亚洲激情视频在线观看| 黄色成人av网| 欧美日韩国产麻豆| 国内精久久久久久久久久人| 91精品国产91久久久久久不卡| 91精品久久久久久久久久入口| 97视频在线观看视频免费视频| 国产成人自拍视频在线观看| 秋霞成人午夜鲁丝一区二区三区| 伦伦影院午夜日韩欧美限制| 国产精品旅馆在线| 成人妇女免费播放久久久| 成人免费福利在线| 91精品视频播放| 国产日韩欧美日韩| 亚洲伊人久久大香线蕉av| www.亚洲人.com| 国产精品视频资源| 日本久久亚洲电影| 91av中文字幕| 成人日韩av在线| 国产亚洲精品久久久| 久久国产精品影视| 国产免费观看久久黄| 亚洲精品丝袜日韩| 国产精品久久一区主播| 亚洲人成网在线播放| 亚洲网站在线播放| 国产精品欧美一区二区| 国产精品偷伦一区二区| 欧美老肥婆性猛交视频| 久久人人爽人人爽人人片av高请| 欧美xxxx综合视频| 亚洲欧洲在线观看| 亚洲精品国偷自产在线99热| www国产精品com| 国产精品一区二区三区久久| 国产91对白在线播放| 日本久久精品视频| 亚洲福利视频久久| 欧美激情奇米色| 欧美一级bbbbb性bbbb喷潮片| 热re91久久精品国99热蜜臀| 在线观看视频99| 欧美最猛性xxxx| 国产美女91呻吟求| 欧美日韩国产在线| 国产日韩精品一区二区| 黑人与娇小精品av专区| 精品久久久av| 亚洲国产成人在线播放| 国产精品扒开腿爽爽爽视频|