项目github地址
绘制过程
绘制背景
首先大海应该是蓝色的吧,而且应该是一个渐变色,那么根据 paint 篇的内容,我们便可以使用 paint.setShader 来实现,实现思路就是使用 Canvas.drawRect 方法绘制整个画布,画笔 Paint 设置一个 Shader,代码如下:
paintBack.shader = LinearGradient( measuredWidth / 3f, 0f, measuredWidth * 2 / 3f, measuredHeight.toFloat(), Color.WHITE, Color.parseColor("#000055"), Shader.TileMode.CLAMP ) 复制代码
canvas.drawRect(background, paintBack) 复制代码
效果大概这个样子
绘制鲸鱼
咳咳,鲸鱼这个东西我在百度上面找了一张图片
而后使用 ps 抠出了其中最漂亮的大蓝鲸,并且使用 ps 液化工具对蓝鲸的尾巴进行了处理,目的就是让蓝鲸在运动的过程中尾巴不停的摆动从而实现游泳的效果
代码:
private val bitmaps = listOf<Bitmap>( BitmapFactory.decodeResource(context.resources, R.drawable.bluefish1), BitmapFactory.decodeResource(context.resources, R.drawable.bluefish2), BitmapFactory.decodeResource(context.resources, R.drawable.bluefish3), BitmapFactory.decodeResource(context.resources, R.drawable.bluefish4), BitmapFactory.decodeResource(context.resources, R.drawable.bluefish3), BitmapFactory.decodeResource(context.resources, R.drawable.bluefish2), BitmapFactory.decodeResource(context.resources, R.drawable.bluefish1), ) 复制代码
canvas.run { drawBitmap(bitmaps[bitmapIndex % bitmaps.size], 100f, 100f, paint) bitmapIndex++ drawFishWithPath() } 复制代码
实现效果:
虎鲸光能摆动尾巴还是不够的,我们还应有让他能做游泳的动作,最好能按照我们指定的路径来运动是最好的了
定义路径的核心代码
fishPath.moveTo(100f, 100f) for (i in 0..20) { fishPath.apply { cubicTo(randowX(), randowY(), randowX(), randowY(), randowX(), randowY()) } } fishPath.close() 复制代码
画出路径效果
这里是有问题的,因为路径转向的时候有很多锐角,可想而知这样是不行的,虎鲸宝宝也不会这么游泳的对吧,这个后续再优化,目前重要的是实现效果
让鱼沿着路径动起来
这里要借助PathMeasure工具了
dstPath.reset() var stop = start+100f pathMeasure.getSegment(start, stop, dstPath, true) val matrix = Matrix() pathMeasure.getMatrix(stop, matrix, (PathMeasure.POSITION_MATRIX_FLAG.or(PathMeasure.TANGENT_MATRIX_FLAG))) val bitmap = bitmaps[bitmapIndex % bitmaps.size] matrix.preTranslate(-bitmap.width / 2f, -bitmap.height / 2f) canvas.drawBitmap(bitmap, matrix, paint) 复制代码
代码是通过pathMeasure.getSegment方法可以截取path,从而在path的某个位置绘制鲸鱼图片,因为能拿到path某个点的正切值,所以我们的鲸鱼可以始终做到沿着切线游泳
游泳效果:
悲剧的是,中间一时忘记录制屏幕,只能把最终效果图放上来了
画太阳和气泡
既然最终效果已经出来了,那么后面直接放画太阳和气泡的代码吧
画太阳
画太阳主要的点在于画周围的阳光。画阳光的时候我们将太阳弧度20等分,然后从两个等分点之间向外画三角就能实现我们的阳光效果了。
path.moveTo(radius + sunX, sunY) val degree = 3.14f * 2 / leafNum for (i in 1..leafNum) { val x1 = radius * cos(i * degree) + sunX val y1 = radius * sin(i * degree) + sunY val halfDegree = (i - 0.5) * degree val shineRadius = radius + Random.nextInt(50) val controllX = shineRadius * cos(halfDegree).toFloat() + sunX val controllY = shineRadius * sin(halfDegree).toFloat() + sunY path.lineTo(controllX, controllY) path.lineTo(x1, y1) } path.close() 复制代码
画气泡
我们使用RadiaGradient镜像渐变的方式实现气泡效果,要注意的点是镜像渐变的颜色中间点不要选在圆心,否则会很难看
paint.shader=RadialGradient(cycleX+40,cycleY-40,radius+300, Color.WHITE,Color.GREEN,Shader.TileMode.CLAMP) canvas.drawCircle(cycleX, cycleY, radius, paint)