https://github.com/rahatarmanahmed/CircularProgressView
View를 상속한 CircularProgressView를 만든다.
public class CircularProgressView extends View
View를 상속하면 최대 4개의 constructor를 구현해야 한다.(보통 여기서 xml에 넣어준 attribute들을 가져와서 설정을 한다.)
constructor에서 attribute들에 대한 값들을 설정하고, 이 값들을 가지고 paint도 설정을 해준다.
(나중에 onDraw에서 그림 그릴때 이렇게 설정된 paint가 사용된다.)
onMeasure와 onSizeChanged로부터 width와 height를 파악해서 작은쪽의 값을 size에 저장하고 bound에는 (left: paddingLeft + thickness, top: paddingTop + thickness, right: size - paddingLeft - thickness, bottom: size - paddingTop - thickness)를 저장한다.
onDraw에서 아래의 코드로 호를 그린다.
canvas.drawArc(bounds, startAngle + indeterminateRotateOffset, indeterminateSweep, false, paint);
호를 startAngle + indeterminateRotateOffset 각도에서 시작해서 indeterminateSweep 크기만큼의 각도로 그린다. 이 세 값은 animator가 업데이트 되어 invalidate()를 호출하기 전에 업데이트 된다.
AnimatorSet을 사용해서 animation set을 만들어 이 set을 실행한다. AnimatorSet의 play()를 통해 animation의 선후관계를 만든다.
이제 가장 중요한 animation을 만들어 보자. 총 4개의 animation을 만든다.
첫번째는 호를 그리는 animation으로 indeterminateSweep(계속 증가)을 변경한다.
두번째는 호를 이동하는 animation으로 indeterminateRotateOffset을 변경한다.
세번째는 호를 줄이는 animation으로 startAngle(증가)과 indeterminateSweep(계속 감소)을 변경한다.
네번째는 두번째와 마찬가지로 호를 이동하는 animation으로 indeterminateRotateOffset을 변경한다.
첫번째를 다시 코드로 자세히 보면, ValueAnimator.ofFloat(start, sweep)을 통해 호를 그리게 될 각도의 interpolation 영역을 지정하고 이의 duration, interpolator도 지정해준다. 그리고 나서 리스너를 달아 값이 나오면 이를 indeterminateSweep에 넣고 invalidate()를 호출한다. 이렇게 함으로서 onDraw에서는 변경된 indeterminateSweep을 가지고 점점 커지는 호를 그리게 된다.
ValueAnimator frontEndExtend = ValueAnimator.ofFloat(INDETERMINANT_MIN_SWEEP, maxSweep); frontEndExtend.setDuration(animDuration/animSteps/2); frontEndExtend.setInterpolator(new DecelerateInterpolator(1)); frontEndExtend.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { indeterminateSweep = (Float) animation.getAnimatedValue(); invalidate(); } });
첫번째와 두번째 animation을 같이 동작시키고, 그 이후에 세번째와 네번째를 같이 동작시킴으로서 안드로이드에서의 material progress bar와 비슷한 형태의 progress bar가 나오게 된다.