Welcome to my official account, "An Anan Android", to learn more knowledge.
Read a good book—— I said
In the previous articles, we talked about Canvas, Paint and Path commonly used in custom controls. In this article, we go further on the basis of the previous articles and draw the effect of an underwater world.
Project github address
Drawing process
Draw background
First of all, the sea should be blue, and it should be a gradient. Then, according to the content of paint, we can use paint Setshader is implemented by using canvas Draw the whole canvas with the drawRect method, and set a Shader with the paint brush. The code is as follows:
paintBack.shader = LinearGradient( measuredWidth / 3f, 0f, measuredWidth * 2 / 3f, measuredHeight.toFloat(), Color.WHITE, Color.parseColor("#000055"), Shader.TileMode.CLAMP )
canvas.drawRect(background, paintBack)
The effect is like this
Drawing whales
Cough, I found a picture of whale on Baidu
Then the most beautiful big blue whale was pulled out with ps, and the tail of the blue whale was treated with ps liquefaction tool. The purpose is to make the tail of the blue whale swing constantly in the process of movement, so as to achieve the effect of swimming
code:
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() }
Effect achieved:
It's not enough for a killer whale to swing its tail. We should also allow him to swim. It's best to follow the path we specify
The core code that defines the path
fishPath.moveTo(100f, 100f) for (i in 0..20) { fishPath.apply { cubicTo(randowX(), randowY(), randowX(), randowY(), randowX(), randowY()) } } fishPath.close()
Draw the path effect
There's a problem here, because there are many sharp angles when the path turns. It's conceivable that this won't work, and the baby killer whale won't swim like this, right? The important thing for subsequent optimization is to achieve the effect
Let the fish move along the path
Here we need to use the PathMeasure tool
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)
The code is through pathmeasure The getsegment method can intercept the path and draw a whale picture at a certain position of the path. Because we can get the tangent value of a point of the path, our whales can always swim along the tangent
Swimming effect:
Unfortunately, I forgot to record the screen in the middle, so I had to put the final effect picture on it
Draw the sun and bubbles
Now that the final effect has come out, let's put the code to draw the sun and bubbles directly behind
Draw the sun
The main point of drawing the sun is to draw the surrounding sunshine. When drawing sunlight, we divide the solar radian into 20 equal parts, and then draw a triangle between the two equal parts to achieve our sunshine effect.
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()
Draw bubbles
We use radiogradient to mirror the gradient to achieve the bubble effect. It should be noted that the middle point of the color of the mirror gradient should not be selected at the center of the circle, otherwise it will be ugly
paint.shader=RadialGradient(cycleX+40,cycleY-40,radius+300, Color.WHITE,Color.GREEN,Shader.TileMode.CLAMP) canvas.drawCircle(cycleX, cycleY, radius, paint)