Canvas的drawXXX方法配合使用Paint可以实现圆点、圆、弧形和曲线等各种颜色的图形,本文将使用drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,@NonNull Paint paint)方法实现奥运五环效果。
先来一张效果图,五环是由五个圆环交叉排列组成,每个圆环有自己圆心和代表颜色,半径和圆环之间的间距固定。关键部分在于确定每个圆环的圆心,解决办法是可以指定一个参考坐标,推算出所有圆环的圆心。方案:1:确定左上角蓝色圆环的圆心,根据半径和间距计算其他圆环圆心坐标;方案2:指定画布(Canvas)宽高,得到其中心坐标(cx,cy),再根据半径和间距计算出所有圆环的圆心坐标。
我选择的是第二种方式实现。原理大致是:
(cx,cy)为画布中心点,即cx = width / 2;cy = height / 2;
因为 h1 = h3,所有 (cx,cy) 也是h2(h2 = 圆环半径 + 圆环间距/2)的中点,到这一步,已经可以确定所有圆环的圆心坐标。
private float mSpace; //圆环之间的间距
private float mStroke; //圆环宽度
private float mRadius; //圆环半径
private PointF o1; //第一个圆环的圆心坐标
private PointF o2; //第二个圆环的圆心坐标
private PointF o3; //第三个圆环的圆心坐标
private PointF o4; //第四个圆环的圆心坐标
private PointF o5; //第五个圆环的圆心坐标
float xCenter = getMeasuredWidth()/2;
float yCenter = getMeasuredHeight()/2;
o1 = new PointF(xCenter-(2*mRadius+mSpace),yCenter-(mRadius+mSpace/2)/2);
o2 = new PointF(xCenter,yCenter-(mRadius+mSpace/2)/2);
o3 = new PointF(xCenter+(2*mRadius+mSpace),yCenter-(mRadius+mSpace/2)/2);
o4 = new PointF(xCenter-(mRadius+mSpace/2),yCenter+(mRadius+mSpace/2)/2);
o5 = new PointF(xCenter+(mRadius+mSpace/2),yCenter+(mRadius+mSpace/2)/2);
圆心确定以后,接下来是画圆弧。因为五环的效果是相互交叉,画的时候也有先后顺序,先画的显示在下面,后画的覆盖在上面。我是通过先后绘制部分弧度的圆环来达到覆盖效果。
private RectF r1; //第一个圆环的矩形区域
private RectF r2; //第二个圆环的矩形区域
private RectF r3; //第三个圆环的矩形区域
private RectF r4; //第四个圆环的矩形区域
private RectF r5; //第五个圆环的矩形区域
r1 = new RectF(o1.x - mRadius,o1.y - mRadius,o1.x + mRadius,o1.y + mRadius);
r2 = new RectF(o2.x - mRadius,o2.y - mRadius,o2.x + mRadius,o2.y + mRadius);
r3 = new RectF(o3.x - mRadius,o3.y - mRadius,o3.x + mRadius,o3.y + mRadius);
r4 = new RectF(o4.x - mRadius,o4.y - mRadius,o4.x + mRadius,o4.y + mRadius);
r5 = new RectF(o5.x - mRadius,o5.y - mRadius,o5.x + mRadius,o5.y + mRadius);
p1 = getPaint(0xff006BB0);
p2 = getPaint(0xff1D1815);
p3 = getPaint(0xffDC2F1F);
p4 = getPaint(0xffEFA90D);
p5 = getPaint(0xff059341);
canvas.drawArc(r1,45,316,false,p1);//多出1度是为了让首尾连接上,避免圆环出现间隙
canvas.drawArc(r4,0,271,false,p4);
canvas.drawArc(r1,0,46,false,p1);
canvas.drawArc(r4,315,46,false,p4);
canvas.drawArc(r2,45,316,false,p2);
canvas.drawArc(r4,270,46,false,p4);
canvas.drawArc(r5,315,316,false,p5);
canvas.drawArc(r2,0,46,false,p2);
canvas.drawArc(r3,0,360,false,p3);
canvas.drawArc(r5,270,46,false,p5);
完整代码:
public class OlympicRingsView extends View {
private Context mContext;
private float viewWidth;
private float viewHeight;
private float mSpace; //圆环之间的间距
private float mStroke; //圆环宽度
private float mRadius; //圆环半径
private PointF o1; //第一个圆环的圆心坐标
private PointF o2; //第二个圆环的圆心坐标
private PointF o3; //第三个圆环的圆心坐标
private PointF o4; //第四个圆环的圆心坐标
private PointF o5; //第五个圆环的圆心坐标
private RectF r1; //第一个圆环的矩形区域
private RectF r2; //第二个圆环的矩形区域
private RectF r3; //第三个圆环的矩形区域
private RectF r4; //第四个圆环的矩形区域
private RectF r5; //第五个圆环的矩形区域
private Paint p1;
private Paint p2;
private Paint p3;
private Paint p4;
private Paint p5;
public OlympicRingsView(Context context) {
this(context,null);
}
public OlympicRingsView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mContext = context;
initAttrs(context, attrs);
}
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.OlympicRingsView, 0, 0);
mRadius = typedArray.getDimension(R.styleable.OlympicRingsView_ringRadius,96);
mStroke = mRadius / 6;
mSpace = mStroke * 2;
typedArray.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
initVariable();
canvas.drawArc(r1,45,316,false,p1);
canvas.drawArc(r4,0,271,false,p4);
canvas.drawArc(r1,0,46,false,p1);
canvas.drawArc(r4,315,46,false,p4);
canvas.drawArc(r2,45,316,false,p2);
canvas.drawArc(r4,270,46,false,p4);
canvas.drawArc(r5,315,316,false,p5);
canvas.drawArc(r2,0,46,false,p2);
canvas.drawArc(r3,0,360,false,p3);
canvas.drawArc(r5,270,46,false,p5);
}
private void initVariable() {
float xCenter = getMeasuredWidth()/2;
float yCenter = getMeasuredHeight()/2;
o1 = new PointF(xCenter-(2*mRadius+mSpace),yCenter-(mRadius+mSpace/2)/2);
o2 = new PointF(xCenter,yCenter-(mRadius+mSpace/2)/2);
o3 = new PointF(xCenter+(2*mRadius+mSpace),yCenter-(mRadius+mSpace/2)/2);
o4 = new PointF(xCenter-(mRadius+mSpace/2),yCenter+(mRadius+mSpace/2)/2);
o5 = new PointF(xCenter+(mRadius+mSpace/2),yCenter+(mRadius+mSpace/2)/2);
r1 = new RectF(o1.x - mRadius,o1.y - mRadius,o1.x + mRadius,o1.y + mRadius);
r2 = new RectF(o2.x - mRadius,o2.y - mRadius,o2.x + mRadius,o2.y + mRadius);
r3 = new RectF(o3.x - mRadius,o3.y - mRadius,o3.x + mRadius,o3.y + mRadius);
r4 = new RectF(o4.x - mRadius,o4.y - mRadius,o4.x + mRadius,o4.y + mRadius);
r5 = new RectF(o5.x - mRadius,o5.y - mRadius,o5.x + mRadius,o5.y + mRadius);
p1 = getPaint(0xff006BB0);
p2 = getPaint(0xff1D1815);
p3 = getPaint(0xffDC2F1F);
p4 = getPaint(0xffEFA90D);
p5 = getPaint(0xff059341);
}
private Paint getPaint(int color){
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(mStroke);
paint.setColor(color);
return paint;
}
}
attrs:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="OlympicRingsView">
<attr name="ringRadius" format="dimension"></attr>
</declare-styleable>
</resources>
Demo下载地址:点击打开链接
喜欢的记得star,mua~