效果
几个要点:
1. 坐标系以左上角为原点,横X竖Y
2. 笔刷Paint
Paint paint = new Paint(); //设置画笔颜色 paint.setColor(getResources().getColor(R.color.arc_fail_color)); //设置画笔的宽度 paint.setStrokeWidth(lineThick); //设置图形为空心 paint.setStyle(Paint.Style.STROKE); //消除锯齿 paint.setAntiAlias(true);
3. 绘制直线
/** Canvas * Draw a line segment with the specified start and stop x,y coordinates, * using the specified paint. * * @param startX The x-coordinate of the start point of the line * @param startY The y-coordinate of the start point of the line * @param paint The paint used to draw the line */ public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint)
4. 绘制圆弧
/** * <p>Draw the specified arc, which will be scaled to fit inside the * specified oval.</p> * * <p>If the start angle is negative or >= 360, the start angle is treated * as start angle modulo 360.</p> * * <p>If the sweep angle is >= 360, then the oval is drawn * completely. Note that this differs slightly from SkPath::arcTo, which * treats the sweep angle modulo 360. If the sweep angle is negative, * the sweep angle is treated as sweep angle modulo 360</p> * * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the * geometric angle of 0 degrees (3 o'clock on a watch.)</p> * * @param oval The bounds of oval used to define the shape and size * of the arc * @param startAngle Starting angle (in degrees) where the arc begins * @param sweepAngle Sweep angle (in degrees) measured clockwise * @param useCenter If true, include the center of the oval in the arc, and close it if it is being stroked. This will draw a wedge * @param paint The paint used to draw the arc */ public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
注:
以时钟三点为0度;
完整角度以360°来计算;
oval限定绘图区域
startAngle为起始角度;
sweepAngle表示划过的角度,如果为负值则逆时针画
useCenter如果为true则画出扇形效果,否则只有一个圆弧
RectF的初始化
/** * Create a new rectangle with the specified coordinates. Note: no range * checking is performed, so the caller must ensure that left <= right and * top <= bottom. * * @param left The X coordinate of the left side of the rectangle * @param top The Y coordinate of the top of the rectangle * @param right The X coordinate of the right side of the rectangle * @param bottom The Y coordinate of the bottom of the rectangle */ public RectF(float left, float top, float right, float bottom)
5. 获取用户在xml中自定义的宽度值 layout_width
public DrawCrossMarkView(Context context, AttributeSet attrs) { super(context, attrs); Pattern p = Pattern.compile("\\d*"); Matcher m = p.matcher(attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_width")); if (m.find()) { totalWidth = Float.valueOf(m.group()); } init(); }
注:
在构造函数中通过getWidth来获取宽度得到的结果往往是0,在执行到onDraw的时候,控件大小才划定;
本例中默认用户以dp为单位设置layout_width。
6. 重写onDraw方法,在没有绘制完成前,通过postInvalidateDelayed定义重绘间隔,每一次重绘,之前绘制的图案都会被清除
//绘制 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.w("check mark", "drawing... # progress=" + progress); if (progress < 100) progress+=step; //根据进度画圆弧 canvas.drawArc(rectF, 235, -360 * progress / 100, false, paint); //先等圆弧画完,画叉 if (progress >= 100) { if (line1X < maxLineIncrement) { line1X+=step; line1Y+=step; } //画第一根线 canvas.drawLine(line1StartX, lineStartY, line1StartX - line1X, lineStartY + line1Y, paint); if (line1X >= maxLineIncrement) { line2X+=step; line2Y+=step; //画第二根线 canvas.drawLine(line2StartX, lineStartY, line2StartX + line2X, lineStartY + line2Y, paint); } } //每隔6毫秒界面刷新 if (line2X < maxLineIncrement) postInvalidateDelayed(6); }
7. 调用
在布局文件中添加控件
<com.xuanzhui.animations.view.DrawCrossMarkView android:layout_width="50dp" android:layout_height="50dp" android:layout_margin="50dp"/>
在color总定义颜色
<color name="arc_fail_color">#D93549</color>
8. 完整代码见 https://github.com/xuanzhui/Animations