弧形進度條(動畫版),弧形進度條動畫版
本部落格只要沒有註明“轉”,那麼均為原創,轉貼請註明本部落格網站連結接
我們先把問題分解為下面3個小問題。
1.如何畫一個弧形
2.如何讓弧形帶有載入過程
3.如何讓進度值隨著圓弧一起轉動
1.我們先看看進度條的樣子
進度條很簡單,一段弧,較長的白色的弧是100%時候的樣子,較短紅色的弧形是當前的進度。
這裡我選用的是圓弧,弧度為240度,這裡要注意一下,我選用的是角度制,之後計算三角函數的時候用的是弧度制,所以還需要進行轉換。
現在我們知道我們要的進度條的樣子了,製作也就有了思路。
先畫一段弧形,240度的,然後再畫一段弧形,圖中進度為7/8=87.5%,那紅色的弧形度數即為240 * 7/8 = 210度。我們只需要在開始的弧上再壓上一段紅色弧形即可。
中的弧形有個特點,兩頭是圓的。所以我們要先設定一下Paint
mPaint = new Paint();mPaint.setAntiAlias(true); //消除鋸齒mPaint.setStyle(Paint.Style.STROKE); //繪製空心圓mPaint.setStrokeWidth(mRingWidth); //設定進度條寬度mPaint.setColor(mRingColor); //設定進度條顏色mPaint.setStrokeJoin(Paint.Join.ROUND);mPaint.setStrokeCap(Paint.Cap.ROUND); //設定圓角
當然我們有兩個弧形,Paint設定類似。
下面我們開始畫弧,代碼大概是下面的樣子
protected void onDraw(Canvas canvas) { canvas.drawArc(...); //完整弧形 canvas.drawArc(...); //紅色進度條弧形 super.onDraw(canvas);}
其中,drawArc是畫弧的函數
public void drawArc (RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
這裡要對startAngle和sweepAngle參數進行解釋一下。
這兩個參數確定了角的兩條邊,startAngle是起始邊,它以原點為中心順時針旋轉sweepAngle度後的位置為終邊。這樣就確定了一個角也就確定了一段圓弧。0度在3點鐘方向,也就是x軸正方向。
的中灰色的那段弧形是多少度到多少度呢,我選擇的是從-210度開始,到30度,幅度為240度。
下面我們可以開始畫弧了。
先確定View的大小,這裡我讓View為一個正方形。取width和height都設定為Math.min(width, height)即可。
知道了View的大小,我們在這個正方形裡面取一個小正方形放在正中間。兩個正方形的距離就是弧形寬度的一半。然後Paint分別像內外各擴散1/2弧寬即可。
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); int sideLength = Math.min(widthSpecSize, heightSpecSize); setMeasuredDimension(sideLength, sideLength);}
下面我們來畫弧
private float mStart = -210;private static final int FULL_ANGLE = 240;@Overrideprotected void onDraw(Canvas canvas) { RectF mBigOval = new RectF(mRingWidth / 2, mRingWidth / 2, getWidth() - (mRingWidth + 1) / 2, getHeight() - (mRingWidth + 1) / 2); canvas.drawArc(mBigOval, mStart, FULL_ANGLE, false, mRemainderPaint); //灰色的弧 canvas.drawArc(mBigOval, mStart, delta, false, mPaint); //紅色的弧 super.onDraw(canvas);}
其中delta就是我們的進度,只不過delta的範圍為0-240。
至此,如何製作弧形進度條已經講完了,下面就是給它加個動畫。
2.動畫也很容易,我們只需要讓delta從0一直變化到我們最終的進度即可
我們實現ValueAnimator.AnimatorUpdateListener介面。
public void setDelta(float delta) { this.delta = delta;}@Overridepublic void onAnimationUpdate(ValueAnimator animation) { invalidate();}
改變delta之後,重新整理View即可。
3.有點難度的是,如何把數字放在上面,讓它隨著進度條一起動起來。
我們知道,每個View都是個矩形,數字是放在一個矩形TextView中,於是問題就變成了如何讓這個矩形圍繞著弧形運行,我們先看下面的這張圖
如果在你程式設計之時,只考慮到弧形正上方的情況,那麼可能會出現如下問題。
a.如果以矩形的底邊到弧形距離作為旋轉時的參照,那麼當矩形旋轉到其他方向的時候(非正上、下、左、右),應該如何選取參照?
如果以矩形的某個頂點到弧形距離作為參照,依然很麻煩,需要考慮四個象限中的不同情形,以及矩形旋轉到弧形正方向時的特殊情況。
b.如果以矩形中心O1到圓心O距離作為旋轉時的參照,那麼情況就會好很多,但是我們看弧形右上方的矩形。旋轉之後矩形與弧形居然相交了!
聰明的同學從圖上可以看出,矩形與圓心距離最近的時候就是矩形的某個頂點旋轉到O與矩形中心的連線上的時候。因為在圓內,從圓心出發的線段半徑最大嘛。知道這個剩下的事情就好辦了,我們只要讓大小圓保持相切(圓心距=R+r)即可,當然,距離更大也可以,就是不太好看。
對於TextView來說,我們甚至可以讓兩個圓稍微相交一點。因為文本不會把TextView填滿。字型大小越大,上下留出的空白就越大。
想知道為什麼會有這麼大空白的同學,請點這裡。另外,Android:includeFontPadding要設定為false!
我們已經知道,讓矩形的中心以一定長度圍繞圓心旋轉即為我們所想要的效果。下面的問題就是如何把這個矩形放到螢幕上面。首先要找出α與矩形中心O2的關係。另外,我們沒有辦法讓android以矩形中心為參照,也就是說,我們要通過α與矩形中心O2的關係找到α與矩形中某個頂點的關係。
我們把圓心距記做D(OO2)。那麼
OA = Dcosα,AO2 = Dsinα
圓心O座標記為(x,y),我們事先是知道弧形的位置的,所以這裡的x和y都是已知的。那麼O2座標為
O2(x+Dcosα, y-Dsinα)
至此,α與矩形中心O2的關係我們已經知道了。下面我們計算一下矩形的左上方頂點B(圖中沒有標出)與α的關係。顯然,我們需要知道矩形的寬和高才行。矩形的大小與字型大小和文字長度有直接關係,這裡採取簡單粗暴的方法,找個TextView放入你想要的文字和樣式,然後量一下……寬和高分別記做w和h。那麼,B的座標即為
B(x+Dcosα-w/2, y-Dsinα-h/2)
最後就是一些細節問題了,比如,這裡的α變化範圍是從210°到-30°。
轉貼請保留以下連結
本人blog地址
http://su1216.iteye.com/
http://blog.csdn.net/su1216/
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。