国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android自定義View實現(xiàn)環(huán)形進度條的思路與實例

2019-10-23 18:30:13
字體:
供稿:網(wǎng)友

前言

前段時間看到了豆瓣FM的音樂播放界面,有一個環(huán)形的進度條,非常的好看,于是想了想,為什么不自己做一個呢,于是就開始了自定義的過程

豆瓣FM的播放界面如下圖:

android,自定義view,環(huán)形進度條,自定義進度條

功能分析

雖然功能比較簡單,但是仍然需要仔細分析

     1.圖標外還有一圈圓圈,可以設置寬度

     2.圓形進度條和進度條底部,可以設置寬度,顏色等

     3.內(nèi)部有一個圓形圖片,可旋轉(zhuǎn)

實現(xiàn)思路分析

1.可以設置寬度的圓圈

這個比較容易,直接在onDraw方法中使用canvas繪制即可,當然,在間距和半徑的處理上需要仔細,控件本體其實還是一個長方形,我們需要選取較短的那一邊作為直徑,同時也要處理內(nèi)部的padding

2.圓形進度條和進度條底部,可以設置寬度,顏色等

這個可以用canvas的drawArc方法來實現(xiàn),通過繪制不同長度的弧形來達到顯示進度的目的,但是需要注意的是,我們需要計算好弧形的半徑以及開始和結(jié)束點。

3.內(nèi)部有一個圓形圖片,可旋轉(zhuǎn)

這個需求可以分為三個部分,有圖片,圓形,可以旋轉(zhuǎn)

先說有圖,很簡單,canvas的drawbitmap方法繪制(canvas真是好東西)

再說圓形,這就比較復雜了,但是整體來說依然是使用canvas來對bitmap進行操作,會在代碼中細說

最后是可以旋轉(zhuǎn),我們可以通過canvas的rotate方法來做。

效果展示

說了這么多,那么最后的效果是怎樣的呢?畢竟空口無憑,在進入代碼展示的環(huán)節(jié)之前還是看看最后的效果吧。

這是我自己做的一個定時鎖屏的項目,地址是這里是地址或者本地下載

這是這個項目運行鎖屏的時候的動圖(大家都喜歡動圖)

android,自定義view,環(huán)形進度條,自定義進度條

代碼實現(xiàn)

下面開始展示代碼,并加以分析

我們主要的工作是在一個自定義的view中的onDraw方法實現(xiàn)的,所以,我們需要有一個繼承View類的子類,我們就叫他MyProgress吧

我們展示的就是這個MyProgress的onDraw方法

1.可以設置寬度的圓圈

很簡單,我們只需要調(diào)用canvas的drawCircle方法即可,但是需要注意對padding的處理,因為不處理就會無效

super.onDraw(canvas); //需要在函數(shù)開始的地方調(diào)用父類的onDraw   final int paddingLeft = getPaddingLeft();  final int paddingRight = getPaddingRight();  final int paddingTop = getPaddingTop();  final int paddingBottom = getPaddingBottom(); //獲取padding   //get the view's width and height and decide the radiu  int width = getWidth() - paddingLeft - paddingRight;  int height = getHeight() - paddingTop - paddingBottom;  radiu = Math.min(width , height) / 2 - boundWidth - progressWidth; //計算半徑,選取長寬中短的那個做處理,boundWidth是圓圈的寬度,progressWidth是進度條的寬度   //setup the paint  paint.setStyle(Paint.Style.STROKE); //設置paint為畫輪廓  paint.setStrokeWidth(boundWidth); //設置寬度  paint.setColor(Color.BLACK);  //設置顏色   //draw the inner circle  int centerX = paddingLeft + getWidth()/2;  int centerY = paddingTop + getHeight() / 2; //計算圓的中心點  canvas.drawCircle(centerX,centerY, radiu, paint); //繪制圓形

2.圓形進度條和進度條底部,可以設置寬度,顏色等

這里需要注意的就是開始的角度和結(jié)束的角度了,為了達到進度條目的,所以我們需要隨著業(yè)務狀態(tài)的改變來改變這個值

  //set paint for arc  paint.setStrokeWidth(progressWidth);  paint.setStrokeCap(Paint.Cap.ROUND);//設置進度寬度,設置末端是一個圓弧   //prepare for draw arc  RectF oval = new RectF();  oval.left = centerX -totalRadiu ;  oval.top =centerY- totalRadiu ;  oval.right = centerX + totalRadiu;  oval.bottom = centerY+ totalRadiu; //新建一個橢圓,設置其四個點的坐標  paint.setColor(progressBackColor);//設置進度條背景的顏色   //draw background arc  canvas.drawArc(oval, arcStar, arcEnd, false, paint); //繪制底部的一個圓弧,作為背景   //draw progress arc  paint.setColor(progressColor);//設置進度條的顏色  canvas.drawArc(oval, arcStar, progress, false, paint);//繪制進度條

3.內(nèi)部有一個圓形圖片,可旋轉(zhuǎn)

這一段比較復雜,直接用代碼解釋

  float totalRadiu = radiu +boundWidth +progressWidth/2;//設置外徑   //draw the circlr pic  if (drawable != null&&bitmap == null) {   image = ((BitmapDrawable) drawable).getBitmap();//獲取設置的bitmap資源    bitmap = Bitmap.createBitmap((int)(2*totalRadiu),(int)(2*totalRadiu), Bitmap.Config.ARGB_8888);   Canvas bitmapCanvas = new Canvas(bitmap);//新建一個bitmap并新建一個canvas用以操作    Paint bitmapPaint = new Paint();   bitmapPaint.setAntiAlias(true);//新建一個paint并設置反鋸齒    bitmapCanvas.drawCircle(totalRadiu, totalRadiu, radiu, bitmapPaint);//畫一個圓    bitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//關鍵代碼,設置為交集模式,會讓后面的內(nèi)容和已有內(nèi)容取交集   bitmapCanvas.drawBitmap(image,null,new RectF(0,0,2*totalRadiu,2*totalRadiu) , bitmapPaint);//繪制自己的圖片到現(xiàn)有畫布上   }  Rect rect = new Rect((int)(centerX -totalRadiu),(int)(centerY-totalRadiu),(int)(centerX+totalRadiu),(int)(centerY+ totalRadiu));//新建一個rect,設定邊界點  canvas.save();  if(isRotate)  canvas.rotate(rotateDegree,centerX,centerY);//設置旋轉(zhuǎn),為了實現(xiàn)圖片轉(zhuǎn)動效果,rotateDegree為旋轉(zhuǎn)角度  canvas.drawBitmap(bitmap,null ,rect, paint);//繪制處理過的圖片

有了上面這些代碼,我們自定義View的主體部分就完成了,當然還有一些輔助的部分,比如更新進度和選擇角度的函數(shù),設置一些顏色和寬度之類的參數(shù)等

完整代碼

MyProgress

public class MyProgressBar extends View { float progress = 360; float arcStar = 270; float arcEnd = 360; double rotateStep = 0.2; Bitmap bitmap; int totalTime; Bitmap image; Drawable drawable; int boundWidth = 5; private int progressWidth = 30; private boolean isRotate = false; private int progressColor = Color.GREEN; private int progressBackColor = Color.GREEN; private float rotateDegree = 0;   public MyProgressBar(Context context) {  super(context); }  public MyProgressBar(Context context, AttributeSet attrs) {  super(context, attrs); }  public MyProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr); }  private float radiu; private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);  public void setRadiu(float radiu) {  this.radiu = radiu;  invalidate(); }//start 函數(shù)使用 countDownTimer類來更新progress和旋轉(zhuǎn)角度 public void start(long time) {  bitmap = null;   time *= 60000;  final float step = (float) 360 / (time / 30);  CountDownTimer mTimer = new CountDownTimer(time, 30) {   public void onTick(long millisUntilFinished) {    progress -= step;    rotateDegree -= rotateStep;    invalidate();   }    @Override   public void onFinish() {    end(step);   }   };  mTimer.start(); }  private void end(float step) {  progress -= step;  invalidate();  progress = 0;  rotateDegree = 0;  invalidate(); }  public void setBoundWidth(int width) {  boundWidth = width; }  public void setProgressWidth(int width) {  progressWidth = width; }  public void setProgressColor(int color) {  progressColor = color; }  public void setProgressBackColor(int color) {  progressBackColor = color; }  public void setDrawable(Drawable drawable) {  this.drawable = drawable;  invalidate(); } public void setIsRote(boolean rotate) {  this.isRotate = rotate;  invalidate(); }  @Override protected void onDraw(Canvas canvas) {  super.onDraw(canvas);   final int paddingLeft = getPaddingLeft();  final int paddingRight = getPaddingRight();  final int paddingTop = getPaddingTop();  final int paddingBottom = getPaddingBottom();   //get the view's width and height and decide the radiu  int width = getWidth() - paddingLeft - paddingRight;  int height = getHeight() - paddingTop - paddingBottom;  radiu = Math.min(width , height) / 2 - boundWidth - progressWidth;   //setup the paint  paint.setStyle(Paint.Style.STROKE);  paint.setStrokeWidth(boundWidth);  paint.setColor(Color.BLACK);   //draw the inner circle  int centerX = paddingLeft + getWidth()/2;  int centerY = paddingTop + getHeight() / 2;  canvas.drawCircle(centerX,centerY, radiu, paint);     float totalRadiu = radiu +boundWidth +progressWidth/2;   //draw the circlr pic  if (drawable != null&&bitmap == null) {   image = ((BitmapDrawable) drawable).getBitmap();    bitmap = Bitmap.createBitmap((int)(2*totalRadiu),(int)(2*totalRadiu), Bitmap.Config.ARGB_8888);   Canvas bitmapCanvas = new Canvas(bitmap);    Paint bitmapPaint = new Paint();   bitmapPaint.setAntiAlias(true);    bitmapCanvas.drawCircle(totalRadiu, totalRadiu, radiu, bitmapPaint);    bitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));   bitmapCanvas.drawBitmap(image,null,new RectF(0,0,2*totalRadiu,2*totalRadiu) , bitmapPaint);    }  Rect rect = new Rect((int)(centerX -totalRadiu),(int)(centerY-totalRadiu),(int)(centerX+totalRadiu),(int)(centerY+ totalRadiu));  canvas.save();  if(isRotate)  canvas.rotate(rotateDegree,centerX,centerY);  canvas.drawBitmap(bitmap,null ,rect, paint);   canvas.restore();  //set paint for arc  paint.setStrokeWidth(progressWidth);  paint.setStrokeCap(Paint.Cap.ROUND);   //prepare for draw arc  RectF oval = new RectF();  oval.left = centerX -totalRadiu ;  oval.top =centerY- totalRadiu ;  oval.right = centerX + totalRadiu;  oval.bottom = centerY+ totalRadiu;  paint.setColor(progressBackColor);   //draw background arc  canvas.drawArc(oval, arcStar, arcEnd, false, paint);   //draw progress arc  paint.setColor(progressColor);  canvas.drawArc(oval, arcStar, progress, false, paint); } }

完整的工程,包括對這個自定義VIEW的應用例子可以參考我在GitHub上的工程地址在這里,也可以本地下載

總結(jié)

這個看似簡單的自定義View的制作當中還是遇到了不少值得思考的問題,這也是為什么有這篇文章的原因

      1.在處理圓形剪裁圖片的時候,要注意剪裁的canvas所用的坐標是相對于處理圖片的,而不是整體坐標

      2.在繪制時,應該盡量減少重復的處理,比如圓形圖片剪裁,一次就夠了,如果次數(shù)過多,每次更新進度的時候就會去進行一次,導致整個View比較卡,進度不準確

      3.對于自定義View中幾個關鍵點的坐標,應該用一個比較簡單易懂的表達式表示,否則做到后期會搞混淆,而陷入坐標的泥潭之中

      4.某些看起來很厲害的效果只要合理分析,分步實現(xiàn),并不會很難

好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對各位Android開發(fā)者們能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網(wǎng)的支持。


注:相關教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 海淀区| 曲松县| 龙胜| 合作市| 合山市| 胶州市| 饶平县| 论坛| 岑溪市| 海淀区| 霞浦县| 自贡市| 兰西县| 海口市| 汕尾市| 嫩江县| 航空| 汉川市| 五常市| 石林| 千阳县| 武城县| 孝义市| 北京市| 佛冈县| 图片| 静安区| 平舆县| 大洼县| 杨浦区| 瓮安县| 黄骅市| 建宁县| 措勤县| 集贤县| 宝鸡市| 前郭尔| 太仆寺旗| 广西| 米泉市| 旬邑县|