您的位置:首页 >聚焦 >

Android从0到1绘制冬奥吉祥物冰墩墩,实现一户一墩

2022-03-01 18:23:32    来源:程序员客栈

北京冬奥虽然已经结束了,但吉祥物冰墩墩的热度依然不减,毫不疑问冰墩墩是今年冬奥名副其实的新晋顶流。现在网上还流传着一句很贴切的话,那就是一“墩”难求。既然身无余“墩”,那就画一个梦中情“墩”,学会绘制冰墩墩,手动实现一户一墩不是梦,赶快学起来吧。

先来看看最终效果图:

根据效果图,我们大概可以看出这得自定义绘制,此冰墩墩基本是由点、矩形、椭圆、圆等常规图形构成,重点还是使用了比较多的曲线绘制而成,常规图形可以使用Canvas绘制,曲线则要使用Path绘制贝塞尔曲线,我们先来回顾一下涉及的知识点。

一、涉及知识点

回顾一下画笔paint涉及的API:

回顾一下canvas绘制涉及的API:

回顾一下path涉及的API:

具体到每个API这里就不展开讲解了,如有需要可以查阅相关资料。

二、实现步骤

1、首先画一个椭圆,如下图所示:

这个还是比较简单的,绘制长半轴在y轴的椭圆,椭圆具体数值短半轴为屏幕宽度/4,长半轴为屏幕高度/6,具体代码如下:

private void init() {//初始化矩阵rectF = new RectF();//创建画笔paint = new Paint();//设置画笔颜色paint.setColor(Color.BLACK);//设置画笔宽度paint.setStrokeWidth(10);//设置画笔填充方法:描边paint.setStyle(Paint.Style.STROKE);//设置抗锯齿paint.setAntiAlias(true);paintBlack.setColor(Color.BLACK);paintBlack.setStrokeWidth(10);paintBlack.setStyle(Paint.Style.FILL);paintBlack.setAntiAlias(true);paintRed.setColor(Color.parseColor("#AA292D"));paintRed.setStrokeWidth(10);paintRed.setStyle(Paint.Style.FILL);paintRed.setAntiAlias(true);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {//设置中心点mCentenWith = w / 2;mCentenHight = h / 2;//设置椭圆长、短半轴mWith = mCentenWith / 2;mHight = mCentenHight / 3;super.onSizeChanged(w, h, oldw, oldh);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制头部//将坐标原点移动到屏幕中心canvas.translate(mCentenWith, mCentenHight);//设置矩阵坐标rectF.set(-mWith, -mHight, mWith, mHight);//画椭圆canvas.drawOval(rectF, paint);}

2、然后再画两个耳朵,并填满颜色,如图所示:

这里绘制用到的是二阶贝塞尔曲线,还涉及到椭圆上的点x、y坐标的确认,根据参数方程:

x=acost;y=bsint;焦点在y轴上,短半轴为a,长半轴为b,t为坐标角度

这里二阶贝塞尔曲线起点设置在椭圆角度为π/5处,而终点设置在椭圆角度为π/3处,具体代码如下所示:

private Path mPathEar1 = new Path();private Path mPathEar2 = new Path();@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制右耳朵// x=acost;y=bsint;焦点在y轴上,短半轴为a,长半轴为b//起点float ear_x1 = (float) (mWith * Math.cos(Math.PI / 5));float ear_y1 = (float) (mHight * Math.sin(Math.PI / 5));//终点float ear_x2 = (float) (mWith * Math.cos(Math.PI / 3));float ear_y2 = (float) (mHight * Math.sin(Math.PI / 3));//移动起点位置mPathEar1.moveTo(ear_x1, -ear_y1);//绘制曲线mPathEar1.quadTo(mWith, -mHight, ear_x2, -ear_y2);canvas.drawPath(mPathEar1, paintBlack);//绘制左耳朵//移动起点位置mPathEar2.moveTo(-ear_x1, -ear_y1);//绘制曲线mPathEar2.quadTo(-mWith, -mHight, -ear_x2, -ear_y2);canvas.drawPath(mPathEar2, paintBlack);}

3、接下来就是绘制冰墩墩的两只手臂啦,在右手臂再画一个小心心在手上颜色填满,如图所示:

这里就要用到三阶贝塞尔曲线啦,这里的难点主要是控制点的坐标不好掌握,我这里绘制的点都是通过测试获取的,所以调试时间还是用的比较多的,最好的请设计帮忙,通过ps给个大致估算,这里只是跟着感觉试出来的,这里的爱心是通过四段三阶贝塞尔曲线合成的爱心,具体代码如下:

private Path mPathHandRight = new Path();private Path mPathHandLeft = new Path(); private Path mPathHeart = new Path();   @Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制右手//终点float hand_x = (float) (mWith * Math.cos(Math.PI / 8));float hand_y = (float) (mHight * Math.sin(Math.PI / 8));//移动起点mPathHandRight.moveTo(mWith, 0);//绘制曲线mPathHandRight.cubicTo(mWith * 7 / 6, -mHight / 2, 2 * mWith, -mHight / 4, hand_x, hand_y);canvas.drawPath(mPathHandRight, paintBlack);//绘制右手红心,这里的爱心是通过四段三阶贝塞尔曲线合成的爱心//重新设置坐标原点,将画布平移到右手位置canvas.translate(mWith * 9 / 7, -mHight / 8);//将画布旋转30度canvas.rotate(30);//移动起点mPathHeart.moveTo(0, -2);//绘制曲线mPathHeart.cubicTo(mWith / 16, -mHight / 16, mWith / 12, -mHight / 16, mWith / 12, 0);canvas.drawPath(mPathHeart, paintRed);//绘制曲线mPathHeart.cubicTo(mWith / 12, 0, mWith / 12, mHight / 16, 0, mHight / 12);canvas.drawPath(mPathHeart, paintRed);//移动起点mPathHeart.moveTo(0, -2);//绘制曲线mPathHeart.cubicTo(-mWith / 16, -mHight / 16, -mWith / 12, -mHight / 16, -mWith / 12, 0);canvas.drawPath(mPathHeart, paintRed);//绘制曲线mPathHeart.cubicTo(-mWith / 12, 0, -mWith / 12, mHight / 16, 0, mHight / 12);canvas.drawPath(mPathHeart, paintRed);//将画布还原回去canvas.rotate(-30);canvas.translate(-mWith * 9 / 7, mHight / 8);//绘制左手//移动起点mPathHandLeft.moveTo(-mWith, 0);//绘制曲线mPathHandLeft.cubicTo(-mWith * 5 / 3, mHight / 2, -mWith * 7 / 6, mHight, -hand_x, hand_y);canvas.drawPath(mPathHandLeft, paintBlack);}

4、接下来就是画冰墩墩的两只脚啦,颜色填满,如图所示:

这里也要用到三阶贝塞尔曲线,控制点也是通过椭圆的长短半轴试出来的,具体代码如下所示:

private Path mPathArmRight = new Path();private Path mPathArmLeft = new Path();@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制右脚//起点float arm_x = (float) (mWith * Math.cos(Math.PI / 3));float arm_y = (float) (mHight * Math.sin(Math.PI / 3));//终点float arm_final_x = (float) (mWith * Math.cos(Math.PI * 4 / 9));float arm_final_y = (float) (mHight * Math.sin(Math.PI * 4 / 9));//移动起点mPathArmRight.moveTo(arm_x, arm_y);//绘制曲线mPathArmRight.cubicTo(arm_x + mWith / 12, mHight * 3 / 2, arm_x / 4, mHight * 3 / 2, arm_final_x, arm_final_y);canvas.drawPath(mPathArmRight, paintBlack);//绘制左脚//移动起点mPathArmLeft.moveTo(-arm_x, arm_y);//绘制曲线mPathArmLeft.cubicTo(-(arm_x + mWith / 12), mHight * 3 / 2, -(arm_x / 4), mHight * 3 / 2, -arm_final_x, arm_final_y);canvas.drawPath(mPathArmLeft, paintBlack);}

5、接下来就是绘制头部轮廓啦,先在内部绘制类似馒头的五环形状,如图所示:

这里主要用到的也是三阶贝塞尔曲线,控制点数值也是模拟出来的,具体如下所示:

private Path mPathBody = new Path();private int[] colors = {Color.parseColor("#88C46A"), Color.parseColor("#E5C267"),Color.parseColor("#6872AE"), Color.parseColor("#AE2C6D"), Color.parseColor("#6CC4F3")};@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制脸部轮廓for (int i = 0; i < 5; i++) {float r = mWith * 7 / 8 - 10 * i;mPathBody.reset();//移动起点mPathBody.moveTo(-r, 0);//控制点float x1 = mWith * 3 / 4 - 10 * i;float y1 = mHight / 2 - 10 * i;mPathBody.cubicTo(-x1, y1, x1, y1, r, 2);//控制点float x2 = mWith - 10 * i;float y2 = mHight * 5 / 4 - 10 * i;mPathBody.cubicTo(x2, -y2, -x2, -y2, -r, 2);//设置颜色paint.setColor(colors[i]);canvas.drawPath(mPathBody, paint);}//还原设置paint.setColor(Color.BLACK);}

6、接下来就是画眼睛啦,画两个椭圆黑眼圈,如图所示:

这里还是比较简单的,就是绘制椭圆,然后通过旋转,具体代码如下所示:

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制右眼睛轮廓//绘制矩阵rectF.set(mWith / 4, -mHight * 2 / 5, mWith * 3 / 4, mHight / 6);//旋转角度canvas.rotate(-40);//绘制椭圆canvas.drawOval(rectF, paintBlack);//还原角度canvas.rotate(40);//绘制左眼睛轮廓//绘制矩阵rectF.set(-mWith / 4, -mHight * 2 / 5, -mWith * 3 / 4, mHight / 6);//旋转角度canvas.rotate(40);//绘制椭圆canvas.drawOval(rectF, paintBlack);//还原角度canvas.rotate(-40);}

椭圆里再画两个大眼睛,如图所示:

这里绘制大眼睛还是比较简单的,就是绘制两个圆,代码如下所示:

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制右眼睛paint.setColor(Color.WHITE);canvas.drawCircle(mWith / 4, -mHight * 2 / 5, mWith / 6, paint);//还原设置paint.setColor(Color.BLACK);//绘制左眼睛paint.setColor(Color.WHITE);canvas.drawCircle(-mWith / 4, -mHight * 2 / 5, mWith / 6, paint);//还原设置paint.setColor(Color.BLACK);}

最后上色,留出眼白,点上高光比较可爱,如图所示:

这里的眼白也是用圆绘制,具体代码如下所示:

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制右眼珠paint.setStyle(Paint.Style.FILL);canvas.drawCircle(mWith / 3, -mHight * 3 / 7, mWith / 20, paint);//还原设置paint.setStyle(Paint.Style.STROKE);//绘制左眼珠paint.setStyle(Paint.Style.FILL);canvas.drawCircle(-mWith / 3, -mHight * 3 / 7, mWith / 20, paint);//还原设置paint.setStyle(Paint.Style.STROKE);}

7、最后绘制冰墩墩的鼻子和嘴巴,如图所示:

这里鼻子就是一个圆,嘴巴用到了二阶贝塞尔曲线和点,这也是比较简单的,具体代码如下所示:

private Path mPathMouse = new Path();@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制鼻子paint.setStyle(Paint.Style.FILL);//绘制圆canvas.drawCircle(0, -mHight / 7, mWith / 20, paint);//绘制嘴巴paint.setStyle(Paint.Style.STROKE);//移动起点mPathMouse.moveTo(mWith / 4, 0);mPathMouse.quadTo(0, mHight / 6, -mWith / 4, 0);canvas.drawPath(mPathMouse, paint);//绘制嘴巴两边的点canvas.drawCircle(mWith / 4, 0, 1, paint);canvas.drawCircle(-mWith / 4, 0, 1, paint);}

到这里自定义的部分就绘制完成啦。

这里就不搞动画绘制了,需要的童鞋自己弄哈,接下来就是使用了,这还是比较简单的,如下所示:

需要源码的童鞋【龙旋】公众号后台回复关键字:冰墩墩,注意这个读墩(dun),别回复错关键字哈。

到这里就搞定啦。

关键词: 如图所示 回顾一下 还是比较

相关阅读