public class BezierCurvePercentView extends View {
//外圈
private Paint paintOutside;
private int paintOutsideColor = Color.parseColor("#FD6F5C");
//背景色
private Paint paintBg;
private int paintBgColor = Color.parseColor("#F4F4F4");
//已使用百分比
private Paint paintPercent;
private int paintPercentColor = Color.parseColor("#FD6F5C");
private Path percentPath;
//文本
private Paint paintText;
private int paintTextColor = Color.parseColor("#ffffff");
private float percent = 0.3f;
/**
* 波纹的长度
*/
private int WAVE_LENGTH = 300;
/**
* 波纹的高度
*/
private final static int WAVE_HEGHT = 20;
private PorterDuffXfermode mMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
private int viewWidth;
private int viewHeight;
private int dx;
public BezierCurvePercentView(Context context) {
super(context);
}
public BezierCurvePercentView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
paintOutside = new Paint();
paintOutside.setAntiAlias(true);
paintOutside.setColor(paintOutsideColor);
paintOutside.setStrokeWidth(3f);
paintOutside.setStyle(Paint.Style.STROKE);
paintBg = new Paint();
paintBg.setAntiAlias(true);
paintBg.setColor(paintBgColor);
paintBg.setStyle(Paint.Style.FILL);
paintPercent = new Paint();
paintPercent.setAntiAlias(true);
paintPercent.setColor(paintPercentColor);
paintPercent.setStyle(Paint.Style.FILL);
percentPath = new Path();
paintText = new Paint();
paintText.setAntiAlias(true);
paintText.setColor(paintTextColor);
paintText.setStrokeWidth(2f);
paintText.setTextSize(100);
paintText.setStyle(Paint.Style.FILL);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewWidth = MeasureSpec.getSize(widthMeasureSpec);
viewHeight = MeasureSpec.getSize(heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int layerId = canvas.saveLayer(0, 0, viewWidth, viewHeight, null, Canvas.ALL_SAVE_FLAG);
canvas.drawCircle(viewWidth/2, viewHeight/2, viewWidth/2-2, paintOutside);
canvas.drawCircle(viewWidth/2, viewHeight/2, viewWidth/2-3, paintBg);
percentPath.reset();
percentPath.moveTo( -WAVE_LENGTH + dx, (1-percent)*viewHeight);
for (int i = -WAVE_LENGTH; i < getWidth() + WAVE_LENGTH; i += WAVE_LENGTH) {
percentPath.rQuadTo(WAVE_LENGTH / 4, -WAVE_HEGHT, WAVE_LENGTH / 2, 0);
percentPath.rQuadTo(WAVE_LENGTH / 4, WAVE_HEGHT, WAVE_LENGTH / 2, 0);
}
percentPath.lineTo(viewWidth, viewHeight);
percentPath.lineTo(0, viewHeight);
percentPath.close();
paintPercent.setXfermode(mMode);
canvas.drawPath(percentPath, paintPercent);
paintPercent.setXfermode(null);
Rect rect = new Rect();
String textStr = (int)(percent*100) + "%";
paintText.getTextBounds(textStr, 0, textStr.length(), rect);
canvas.drawText(textStr, viewWidth/2 - rect.width()/2, viewHeight/2 + rect.height()/2, paintText);
canvas.restoreToCount(layerId);
}
public void setPercent(float percent){
this.percent = percent;
ValueAnimator mValueAnimator = ValueAnimator.ofInt(0, WAVE_LENGTH);
mValueAnimator.setDuration(2000);
mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
// 动画插值器,也可以使用其他
mValueAnimator.setInterpolator(new LinearInterpolator());
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
dx = ( int ) animation.getAnimatedValue();
invalidate();
}
});
mValueAnimator.start();
}
}
二阶贝塞尔曲线的两个方法 quadTo 与 rQuadTo
path.moveTo(x, y);
quadTo(x1, y1, x2, y2);
quadTo(x3, y3, x4, y4);
此方法中的每个坐标是相对起点的坐标,即 x1-x = x2-x1 = x3-x2 = x4-x3;
path.moveTo(x, y);
rQuadTo(x1, y1, x2, y2);
rQuadTo(x3, y3, x4, y4);
此方法中的每个坐标是相对上一个点的坐标,假设起点是(0, 0),波长是100,波高度20,则:
path.moveTo(0, 0);
rQuadTo(100/4, 20,100/2, 0);
↓↓↓第二段曲线 (x,y)把上一个点看做(0, 0)即相对上一个点X位移量为1/4波长=100/4,Y减少波高度20
rQuadTo(100/4, -20, 100/2, 0);
完整曲线共5个点,如下图:
path.moveTo(起点x, 起点y);
quadTo(Ax, Ay, Bx, By);
quadTo(Cx, Cy, Dx, Dy);
二阶贝塞尔.jpg
网友评论