Android使用Canvas实现奥运五环

     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~



        

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值