上一篇博客弄了個自定義樣式的等待對話框,裏面那個圓形progressBar只是隨便用了環形的shape來佈局,後來發現真的醜得不要不要的,所以手動畫了一個圓點progress。y由於個人是不喜歡在開發APP的時候放大型的圖片或者gif圖這些會增加APP體積之類的東西,所以那些規則的圖形和動畫基本上都喜歡用代碼畫出來,雖然有點磨時間,但最後項目後期和做ios版本的同事相比,喜歡放圖片的同事做出來的APP體積有20多M,而我做出來的只有4.5M,確實有點成就感。
好吧,不多說,封裝了以後直接用。
效果圖:
自定義view的步驟就不多說了,前面的博客已經寫過了,所以直接上代碼,代碼裏註釋很清楚:
無非就是在大圓軌跡上根據畫小圓,關鍵是需要用到幾何的正餘弦計算。
attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleProgress">
<attr name="numOfCircles" format="integer"/>
<attr name="maxRadius" format="dimension"/>
<attr name="minRadius" format="dimension"/>
<attr name="rotateSpeedInMillis" format="integer"/>
<attr name="isClockwise" format="boolean"/>
<attr name="circleColor" format="color"/>
</declare-styleable>
</resources>
CircleProgress.java
public class CircleProgress extends View{
//小圓的個數
private int numOfCircles;
//最大圓半徑
private int maxRadius;
//最小圓半徑
private int minRadius;
//旋轉速度
private int rotateSpeedInMillis;
//是否順時針旋轉
private boolean isClockwise;
//小圓的顏色
private int circleColor;
private Paint paint;
private float rotateDegrees;
private int numOfRotate;
public CircleProgress(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.CircleProgress);
numOfCircles=array.getInt(R.styleable.CircleProgress_numOfCircles, 10);
maxRadius=array.getDimensionPixelSize(R.styleable.CircleProgress_maxRadius, dp2px(10));
minRadius=array.getDimensionPixelSize(R.styleable.CircleProgress_minRadius, dp2px(2));
rotateSpeedInMillis=array.getInt(R.styleable.CircleProgress_rotateSpeedInMillis, 200);
isClockwise=array.getBoolean(R.styleable.CircleProgress_isClockwise, true);
circleColor=array.getColor(R.styleable.CircleProgress_circleColor, Color.BLACK);
array.recycle();
paint=new Paint();
paint.setStyle(Style.FILL);
paint.setAntiAlias(true);
paint.setColor(circleColor);
//view每次旋轉的角度
rotateDegrees=360/numOfCircles;
//旋轉的週期爲小圓的個數
numOfRotate=0;
}
public CircleProgress(Context context, AttributeSet attrs) {
this(context, attrs, 0);
// TODO Auto-generated constructor stub
}
public CircleProgress(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
//按一定角度旋轉畫布canvas,當旋轉週期==小圓個數時重置
if(numOfRotate==numOfCircles){
numOfRotate=0;
}
//根據旋轉的方向旋轉畫布canvas,然後再畫小圓
if(isClockwise){
canvas.rotate(rotateDegrees*numOfRotate, getWidth()/2, getHeight()/2);
}else{
canvas.rotate(-rotateDegrees*numOfRotate, getWidth()/2, getHeight()/2);
}
//記錄旋轉的次數,下次invalidat()重繪時就可以使用新的角度旋轉canvas,使小圓產生旋轉的感覺
numOfRotate++;
//取View最短邊,並減去最大圓的半徑,得到所有圓所在的圓路徑的半徑
int radius=(getWidth()>getHeight()?getHeight():getWidth())/2-maxRadius;
//每個小圓的半徑增量
float radiusIncrement=(float)(maxRadius-minRadius)/numOfCircles;
//每隔多少度繪製一個小圓,弧度制
double angle=2*Math.PI/numOfCircles;
//按位置畫小圓
//每個小圓的位置可以由正弦餘弦函數求出,並且每個小圓半徑依次遞增,若反方向則依次遞減
if(isClockwise){
for(int i=0; i<numOfCircles; i++){
float x=(float) (getWidth()/2+Math.cos(i*angle)*radius);
float y=(float) (getHeight()/2-Math.sin(i*angle)*radius);
canvas.drawCircle(x, y, maxRadius-radiusIncrement*i, paint);
}
}else{
for(int i=0; i<numOfCircles; i++){
float x=(float) (getWidth()/2+Math.cos(i*angle)*radius);
float y=(float) (getHeight()/2-Math.sin(i*angle)*radius);
canvas.drawCircle(x, y, minRadius+radiusIncrement*i, paint);
}
}
//旋轉間隔,即progressBar的旋轉速度
postDelayed(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
invalidate();
}
}, rotateSpeedInMillis);
}
//dp轉px函數
private int dp2px(int dp){
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
}
代碼下載: github