前言
這次練習做了一個簡單的Circle Progress,產生幾個圓形,再利用Animator物件幫我們達到持續旋轉的效果,效果如下。
以下我歸納為幾個實作步驟:
- 初始化
- 於量測階段(onMeasure)設定大小
- 於大小確定階段設置基本資源和動畫
- 於繪製階段繪製所需圓形
初始化
初始化就如同先前的篇章提到的方式,若你希望提供更多的屬性來客製化,就設定自己所需要的屬性資源即可,這邊我直接使用簡單的方式,直接設定單一顏色即可。
private void init() {
this.viewWidth = 150;
this.viewHeight = 150;
this.color = Color.parseColor("#FF4081");
this.numberOfCircle = 6;
this.rotates = new float[this.numberOfCircle];
}
CircleProgress的寬高就直接設置150、顏色固定為粉紅色,本身的圓圈和後面跟隨的小圓圈共有六個,當然你可以提供客製化需求,自定義attrs的設定即可。
於量測階段(onMeasure)設定大小
onMeasure這個方法是View的生命週期(LifeCycle)之一,其實相似於Activity或Fragment的生命週期,就是一個View從無到繪製出來的一個過程,然而onMeasure是在View初始化時,需要先對我們的佈局及當中的子視圖進行量測的一個階段,我們在這個階段可以取得量測的大小,或是直接設定我們所要的尺寸,以下我直接將viewWidth=150和viewHeight=150透過setMeasuredDimension方法存取,程式碼如下。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int measuredWidth = resolveSize(this.viewWidth, widthMeasureSpec);
final int measuredHeight = resolveSize(this.viewHeight, heightMeasureSpec);
this.setMeasuredDimension(measuredWidth, measuredHeight);
}
於大小確定階段設置基本資源和動畫
onLayout階段則是佈局與子視圖都已經確定其大小和位置的階段,這時我們就可以進行我們圓形繪製的前置準備,程式碼如下。
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
this.initLayoutSize();
this.initCircles();
this.prepareAnim();
}
private void initLayoutSize() {
this.onLayoutWidth = this.getWidth();
this.onLayoutHeight = this.getHeight();
this.center = new PointF(this.onLayoutWidth / 2.0f, this.onLayoutHeight / 2.0f);
}
private void initCircles() {
final float size = Math.min(this.onLayoutWidth, this.onLayoutHeight);
final float circleRadius = size / 10.0f;
this.circles = new Circle[this.numberOfCircle];
for (int i = 0; i < this.numberOfCircle; i++) {
this.circles[i] = new Circle();
this.circles[i].setCenter(this.center.x, circleRadius);
this.circles[i].setColor(this.color);
this.circles[i].setRadius(circleRadius - circleRadius * i / 6);
}
}
private void prepareAnim() {
for (int i = 0; i < this.numberOfCircle; i++) {
final int index = i;
ValueAnimator fadeAnimator = ValueAnimator.ofFloat(360, 0, 0, 360);
fadeAnimator.setRepeatCount(ValueAnimator.INFINITE);
fadeAnimator.setDuration(2500);
fadeAnimator.setStartDelay(index * 100);
fadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
rotates[index] = (float) animation.getAnimatedValue();
reDraw();
}
});
fadeAnimator.start();
}
}
private void reDraw() {
this.invalidate();
}
於繪製階段繪製所需圓形
最後一步則是於onDraw階段繪製我們所有的圓形即可,程式碼如下。private void drawGraphic(Canvas canvas) {
for (int i = 0; i < this.numberOfCircle; i++) {
canvas.save();
canvas.rotate(this.rotates[i], this.center.x, this.center.y);
this.circles[i].draw(canvas);
canvas.restore();
}
}