1. 程式人生 > >Andorid 自定義圓形漸變色進度條的從實現到開源

Andorid 自定義圓形漸變色進度條的從實現到開源

寫在前面的話

3月初我在自定義控制元件概述中挖下的幾個坑,前一段時間已經基本填完了,自定義控制元件的幾種實現方式也分別寫了demo來進行說明。今天我們來聊一聊如何把自己封裝一個圓形漸變色進度條控制元件開源到github,並且上傳到jcenter方便別人遠端依賴。先看下效果圖:

N0ckzIs

連線github並提交新專案

前提條件:

  1. 安裝Git客戶端(下載地址

建立新專案並提交到Github:

  1. 在AndroidStudio中新建一個專案
  2. 配置Git:Settings -> Version Control -> Git ,設定git目錄,點選Test測試,如果成功會有Success提示

Wv6s1jw

3. 關聯自己的Github賬號:Settring -> VersionControl ->GitHub,設定自己的github賬號,密碼,點選Test測試,如果成功會有Success提示

7ZGSmgQ

4. 分享專案:VCS -> Import into Version Control -> Share Project on GitHub, 點選之後開始設定 repository name(如果你有設定過MasterPassword 會彈出對話方塊讓填入密碼)

kg5inwD

點選Share之後, 你就可以在GitHub上看到新的倉庫,同時在AndroidStudio中CVS下也可以看到版本控制Git,這樣就已經設定成功。

5. 如果你想解除關聯,只需要Settrings -> Version Control刪掉關聯就可以了。

完成circlebar程式碼

接下來我們來實現我們的圓形漸變色進度條,需要的技能:

  • Canvas繪圖基礎
  • Shader繪製漸變色
  • 繪製進度條的原理

Canvas繪圖基礎

關於Canvas繪圖,網上的教程很多,這裡大概的說一下都有哪些點需要了解:

  • Canvas座標系與繪圖座標系。
  • drawARGB:Canvas中的drawARGB可以用來對整個Canvas以某種統一的顏色整體繪製,四個引數分別是Alpha、Red、Green、Blue,取值都是0-255。
  • drawText:Canvas中用drawText方法繪製文字。
  • drawPoint:Canvas中用drawPoint方法繪製點。
  • drawLine:Canvas通過drawLine方法繪製一條線段,通過drawLines方法繪製多段線。
  • drawRect:Canvas通過drawRect方法繪製矩形。
  • drawCircle:Canvas中用drawCircle方法繪製圓形。
  • drawOval:Canvas中提供了drawOval方法繪製橢圓。
  • drawArc:Canvas中提供了drawArc方法用於繪製弧,這裡的弧指兩種:弧面和弧線,弧面即用弧圍成的填充面,弧線即為弧面的輪廓線。
  • drawPath:Canvas通過drawPath方法可以繪製Path。那Path是什麼呢?Path致以過來是路徑的意思,在Android中,Path是一種線條的組合圖形,其可以由直線、二次曲線、三次曲線、橢圓的弧等組成。Path既可以畫線條,也可以畫填充面。
  • drawBitmap:Canvas中提供了drawBitmap方法用於繪製Bitmap。

Paint和Shader

Paint

  • 畫筆Paint控制著所繪製的圖形的具體外觀,Paint預設的字型大小為12px,在繪製文字時我們往往要考慮密度density設定合適的字型大小。畫筆的預設顏色為黑色,預設的style為FILL,預設的cap為BUTT,預設的線寬為0.
  • 在畫面狀的圖形時,如果Paint的style是FILL,那麼繪製的就是填充面;如果是STROKE,那麼繪製的就是輪廓線。

Shader

androd 提供了Shader類專門用來渲染影象以及一些幾何圖形。Shader下面包括幾個直接子類,分別是BitmapShader、 ComposeShader、LinearGradient、RadialGradient、SweepGradient。BitmapShader主要用來渲染影象,LinearGradient 用來進行梯度渲染,RadialGradient 用來進行環形渲染,SweepGradient 用來進行梯度渲染,ComposeShader則是一個 混合渲染,可以和其它幾個子類組合起來使用。

Shader類的使用,都需要先構建Shader物件,然後通過Paint的setShader方法設定渲染物件,然後設定渲染物件,然後再繪製時使用這個Paint物件即可。

繪製進度條

talk is cheap,show you my code。下面說一下繪製圓形漸變進度條的過程。

首先先跟大家說下原理,我們的主要繪製過程其實非常簡單,呼叫drawArc方法繪製圓弧

先來說下drawArc方法。

Java /** * 繪製弧 * drawArc (RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) * oval是RecF型別的物件,其定義了橢圓的形狀 * startAngle指的是繪製的起始角度,鐘錶的3點位置對應著0度,如果傳入的startAngle小於0或者大於等於360,那麼用startAngle對360進行取模後作為起始繪製角度。 * sweepAngle指的是從startAngle開始沿著鐘錶的順時針方向旋轉掃過的角度。如果sweepAngle大於等於360,那麼會繪製完整的橢圓環。如果sweepAngle小於0,那麼會用sweepAngle對360進行取模後作為掃過的角度。 * useCenter是個boolean值,如果為true,表示在繪製完環之後,用橢圓的中心點連線環上的起點和終點以閉合環;如果值為false,表示在繪製完環之後,環的起點和終點直接連線,不經過橢圓的中心點。 */
12345678 /**  * 繪製弧  * drawArc (RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)  * oval是RecF型別的物件,其定義了橢圓的形狀  * startAngle指的是繪製的起始角度,鐘錶的3點位置對應著0度,如果傳入的startAngle小於0或者大於等於360,那麼用startAngle對360進行取模後作為起始繪製角度。  * sweepAngle指的是從startAngle開始沿著鐘錶的順時針方向旋轉掃過的角度。如果sweepAngle大於等於360,那麼會繪製完整的橢圓環。如果sweepAngle小於0,那麼會用sweepAngle對360進行取模後作為掃過的角度。  * useCenter是個boolean值,如果為true,表示在繪製完環之後,用橢圓的中心點連線環上的起點和終點以閉合環;如果值為false,表示在繪製完環之後,環的起點和終點直接連線,不經過橢圓的中心點。  */

裡邊需要傳一個定義好的矩形

Java /** *RectF rectF = new RectF(100, 100, 300, 300); * 這四個引數分別代表的意思是:left top right bottom 左 上 右 下 * left : 矩形左邊的X座標 * top: 矩形頂部的Y座標 * right : 矩形右邊的X座標 * bottom: 矩形底部的Y座標 * 其實就是矩形的左上角和右下角的座標值 */
123456789 /**  *RectF rectF = new RectF(100, 100, 300, 300);  * 這四個引數分別代表的意思是:left   top   right   bottom  左 上 右 下  * left : 矩形左邊的X座標  * top:    矩形頂部的Y座標  * right :  矩形右邊的X座標  * bottom: 矩形底部的Y座標  * 其實就是矩形的左上角和右下角的座標值  */

接下來我們來看一個小例子,自定義view,在ondraw中呼叫如下方法:

Java //繪製矩形框和圓弧 private void drawArc(Canvas canvas) { canvas.drawARGB(255, 56, 197, 186); RectF rectF = new RectF(100, 100, 300, 300); paint.setStrokeWidth(1 * density);//設定線寬 paint.setColor(0xFF6BB7ED);//設定顏色 paint.setStyle(Paint.Style.FILL);//預設設定畫筆為填充模式 //繪製橢圓 paint.setStyle(Paint.Style.STROKE);//設定畫筆為線條模式 canvas.drawArc(rectF, 0, 359, false, paint); paint.setStrokeWidth(1 * density);//設定線寬 paint.setColor(0xff8bc5ba);//設定顏色 paint.setStyle(Paint.Style.STROKE);//預設設定畫筆為填充模式 canvas.drawRect(rectF, paint); }
123456789101112131415161718192021 //繪製矩形框和圓弧privatevoiddrawArc(Canvas canvas){canvas.drawARGB(255,56,197,186);RectF rectF=newRectF(100,100,300,300);paint.setStrokeWidth(1*density);//設定線寬paint.setColor(0xFF6BB7ED);//設定顏色paint.setStyle(Paint.Style.FILL);//預設設定畫筆為填充模式//繪製橢圓paint.setStyle(Paint.Style.STROKE);//設定畫筆為線條模式canvas.drawArc(rectF,0,359,false,paint);paint.setStrokeWidth(1*density);//設定線寬paint.setColor(0xff8bc5ba);//設定顏色paint.setStyle(Paint.Style.STROKE);//預設設定畫筆為填充模式canvas.drawRect(rectF,paint);}

效果如下圖:

VJ0oCyl

我們看到當我們以同一個矩形rectF為基準畫了一個圓弧和矩形,圓弧正好為矩形的內切圓。這時候我們增大圓弧的線寬為21*density。效果如下圖:

MoYmQXp

可以看到圓弧以矩形為基準寬度向矩形外和矩形內各增大了10*density。

這時候我們以rectF為基準再多畫一個圓弧。

Java paint.setStrokeWidth(11 * density);//設定線寬 paint.setColor(0xFF303f9f);//設定顏色 paint.setStyle(Paint.Style.FILL);//預設設定畫筆為填充模式 paint.setStrokeCap(Paint.Cap.ROUND); paint.setStyle(Paint.Style.STROKE);//設定畫筆為線條模式 canvas.drawArc(rectF, 0, 270, false, paint);
1234567 paint.setStrokeWidth(11*density);//設定線寬paint.setColor(0xFF303f9f);//設定顏色paint.setStyle(Paint.Style.FILL);//預設設定畫筆為填充模式paint.setStrokeCap(Paint.Cap.ROUND);paint.setStyle(Paint.Style.STROKE);//設定畫筆為線條模式canvas.drawArc(rectF,0,270,false,paint);

效果如下:

0jJRZy2

perfect!可以看到我們要的效果基本已經出來了。

然後說一下具體的一些細節。

onmeasure,我們在裡邊去設定控制元件的大小為正方形:

Java @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec); int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec); int min = Math.min(width, height);// 獲取View最短邊的長度 setMeasuredDimension(min, min);// 強制改View為以最短邊為長度的正方形 circleStrokeWidth = Textscale(35, min);// 圓環的寬度 pressExtraStrokeWidth = Textscale(2, min);// 圓環離矩形的距離 /** * 這四個引數分別代表的意思是:left top right bottom 左 上 右 下 * left : 矩形左邊的X座標 * top: 矩形頂部的Y座標 * right : 矩形右邊的X座標 * bottom: 矩形底部的Y座標 * 其實就是矩形的左上角和右下角的座標值 */ mColorWheelRectangle.set(circleStrokeWidth + pressExtraStrokeWidth, circleStrokeWidth + pressExtraStrokeWidth, min - circleStrokeWidth - pressExtraStrokeWidth, min - circleStrokeWidth - pressExtraStrokeWidth);// 設定圓環內圓的外接正方形 mColorWheelPaint.setStrokeWidth(circleStrokeWidth - 5); mColorWheelPaintCentre.setStrokeWidth(circleStrokeWidth + 5); mDefaultWheelPaint.setStrokeWidth(circleStrokeWidth - Textscale(2, min)); mDefaultWheelPaint.setShadowLayer(Textscale(10, min), 0, 0, Color.rgb(127, 127, 127));// 設定陰影 }
123456789101112131415161718192021222324252627 @OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){intheight=getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec);intwidth=getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec);intmin=Math.min(width,height);// 獲取View最短邊的長度setMeasuredDimension(min,min);// 強制改View為以最短邊為長度的正方形circleStrokeWidth=Textscale(35,min);// 圓環的寬度pressExtraStrokeWidth=Textscale(2,min);// 圓環離矩形的距離/**     * 這四個引數分別代表的意思是:left   top   right   bottom  左 上 右 下     * left : 矩形左邊的X座標     * top:    矩形頂部的Y座標     * right :  矩形右邊的X座標     * bottom: 矩形底部的Y座標     * 其實就是矩形的左上角和右下角的座標值     */mColorWheelRectangle.set(circleStrokeWidth+pressExtraStrokeWidth,circleStrokeWidth+pressExtraStrokeWidth,min-circleStrokeWidth-pressExtraStrokeWidth,min-circleStrokeWidth-pressExtraStrokeWidth);// 設定圓環內圓的外接正方形mColorWheelPaint.setStrokeWidth(circleStrokeWidth-5);mColorWheelPaintCentre.setStrokeWidth(circleStrokeWidth+5);mDefaultWheelPaint.setStrokeWidth(circleStrokeWidth-Textscale(2,min));mDefaultWheelPaint.setShadowLayer(Textscale(10,min),0,0,Color.rgb(127,127,127));// 設定陰影}

定義了一個setShaderColor方法來設定漸變色,這裡我們用梯度漸變。

Java /** * 設定漸變色 * * @param shaderColor */ public void setShaderColor(int[] shaderColor) { this.mColors = shaderColor; Shader newShader = new SweepGradient(0, 0, mColors, null); mColorWheelPaint.setShader(newShader); }
12345678910 /** * 設定漸變色 * * @param shaderColor */publicvoidsetShaderColor(int[]shaderColor){this.mColors=shaderColor;Shader newShader=newSweepGradient(0,0,mColors,null);mColorWheelPaint.setShader(newShader);}

最後繼承Animation類自定義一個動畫效果,即根據進度計算角度,來慢慢繪製我們的進度條。

Java /** * 進度條動畫 * * @author Administrator */ public class BarAnimation extends Animation { public BarAnimation() { } /** * 每次系統呼叫這個方法時, 改變mSweepAnglePer,mPercent,stepnumbernow的值, * 然後呼叫postInvalidate()不停的繪製view。 */ @Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); if (interpolatedTime < 1.0f) { mPercent = Float.parseFloat(fnum.format(interpolatedTime * stepnumber * 100f / stepnumbermax));// 將浮點值四捨五入保留一位小數 mSweepAnglePer = interpolatedTime * stepnumber * 360 / stepnumbermax; stepnumbernow = (int) (interpolatedTime * stepnumber); } else { mPercent = Float.parseFloat(fnum.format(stepnumber * 100f / stepnumbermax));// 將浮點值四捨五入保留一位小數 mSweepAnglePer = stepnumber * 360 / stepnumbermax; stepnumbernow = stepnumber; } postInvalidate(); } }
123456789101112131415161718192021222324252627282930313233 /** * 進度條動畫 * * @author Administrator */publicclassBarAnimationextendsAnimation{publicBarAnimation(){}/**     * 每次系統呼叫這個方法時, 改變mSweepAnglePer,mPercent,stepnumbernow的值,     * 然後呼叫postInvalidate()不停的繪製view。     */@OverrideprotectedvoidapplyTransformation(floatinterpolatedTime,Transformationt){super.applyTransformation(interpolatedTime,t);if(interpolatedTime<1.0f){mPercent=Float.parseFloat(fnum.format(interpolatedTime*stepnumber*100f/stepnumbermax));// 將浮點值四捨五入保留一位小數mSweepAnglePer=interpolatedTime*stepnumber*360/stepnumbermax;stepnumbernow=(int)(interpolatedTime*stepnumber);}else{mPercent=Float.parseFloat(fnum.format(stepnumber*100f/stepnumbermax));// 將浮點值四捨五入保留一位小數mSweepAnglePer=stepnumber*360/stepnumbermax;stepnumbernow=stepnumber;}postInvalidate();}}

好了,到這裡我們的自定義圓形漸變色進度條就完全搞定了。

上傳到jcenter

步驟如下:

  1. 註冊bintray.com賬號,註冊地址
  2. 引入bintray-release,在需要上傳的module裡面填寫相關publish的資訊
  3. 呼叫上傳的命令
  4. Add to Jcenter提交稽核

需要注意的是,這裡我遇到了一個問題,在這裡跟大家分享一下,即當我上傳的moudle中帶有中文註釋,編碼為utf-8的時候,上傳會丟擲異常,然後上傳失敗。從網上也沒有找到太好的解決辦法,最後我把中文中是全部刪掉才上傳成功。如果你有好的解決辦法,請告訴我0.0

結語

最後,歡迎大家關注我的微信公眾號:CoderTopia。