这里我们选择第一个构造方法。由于设置渐变需要每次都创建一个新的 SweepGradient 对象,所以最好不要放到 onDraw 方法中去更新,最好在初始化的时候就设置好,避免频繁创建导致内存抖动。
private void updateArcPaint() { // 设置渐变 int[] mGradientColors = {Color.GREEN, Color.YELLOW, Color.RED}; mSweepGradient = new SweepGradient(mCenterPoint.x, mCenterPoint.y, mGradientColors, null); mArcPaint.setShader(mSweepGradient); }这里还有一个值得注意的地方,草图如下
假设,渐变颜色如下:
int[] mGradientColors = {Color.GREEN, Color.YELLOW, Color.RED, Color.BLUE};因为 SweepGradient 渐变是 360 度的,所以如果你绘制的圆弧只有 270度,则蓝色部分(图中黑色阴影部分)的渐变就会不可见。
接下来,就是文字的绘制了。文字绘制在上述提到的文章中已经进行了详细的讲解,这里就不再赘述。代码如下:
private void drawText(Canvas canvas) { canvas.drawText(String.format(mPrecisionFormat, mValue), mCenterPoint.x, mValueOffset, mValuePaint); if (mHint != null) { canvas.drawText(mHint.toString(), mCenterPoint.x, mHintOffset, mHintPaint); } if (mUnit != null) { canvas.drawText(mUnit.toString(), mCenterPoint.x, mUnitOffset, mUnitPaint); } }最后,我们来实现进度条的动画效果。这里我们使用 Android 的属性动画来实现进度更新。
private void startAnimator(float start, float end, long animTime) { mAnimator = ValueAnimator.ofFloat(start, end); mAnimator.setDuration(animTime); mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mPercent = (float) animation.getAnimatedValue(); mValue = mPercent * mMaxValue; if (BuildConfig.DEBUG) { Log.d(TAG, "onAnimationUpdate: percent = " + mPercent + ";currentAngle = " + (mSweepAngle * mPercent) + ";value = " + mValue); } invalidate(); } }); mAnimator.start(); }这里有两个注意点:
1. 不要在 ValueAnimator.AnimatorUpdateListener 中输出 Log,特别是动画调用频繁的情况下,因为输出 Log 频繁会生成大量 String 对象造成内存抖动,当然也可以使用 StringBuilder 来优化。
2. 关于 invalidate() 和 postInvalidate() 两者最本质的前者只能在 UI 线程中使用,而后者可以在非 UI 线程中使用,其实 postInvalidate() 内部也是使用 Handler 实现的。
关于 Android 属性动画可以参考:
1. Android 属性动画(Property Animation) 完全解析 (上)
2. Android 属性动画(Property Animation) 完全解析 (下)
补充:同一个属性如何支持颜色和颜色数组