preface

Think about the audio and video may have to first put a paragraph, can only intermittently to update, because recently really a little confused about this aspect, the knowledge system of cross-facing taobao department bosses gave me is really too large, I still have to learn to do a good job in Java layer first, and then advanced. Focus on Java and Flutter first. However, the project will probably be done in Kotlin as much as possible. After all, this is probably the mainstream language of Alibaba now. After all, it is Kotlin that will be presented at the cloud Computing conference, not Java.

Gtihub portal

directory

  1. Real cool custom View (1)
  2. Custom View (2)
  3. Custom View (3)

Basic use of Paint and Canvas

In the previous article, did you touch Android custom View thoroughly? Where we know about overdrawing the View, overdrawing things like that. This is the basis, but Paint and Canvas are also very important basis, they are colloquial words, pen and Canvas, and so many painting tasks are not done by them?

We talked about audio and video development before, and the concept of video, which we already know about, is that a frame of picture, drawn faster than the human eye, can be transformed into video.

The above shows the process of drawing a Bezier curve, which I have already implemented in code. Interested readers can go directly to the source of the PathView class to view.

In fact, I only simulated 100 times, but you can feel the whole image is moving, which is actually a principle of animation implementation.

The simulation of this Bezier curve, in fact, can be divided into several parts, the two same parts are the Bezier curve the simulation of a line and a point, and the intermediate point, which is the position change simulation of the Bezier curve.

This is where we need to pay attention to how to get the position of the current dot. Obviously, using Paint and Canvas is not enough, because our dot needs to be computed by position transformation. Here we’re going to introduce our own class Path.

Path

A Path b Path C Path D Path

First, let’s have a look at its function. It may be different from Canvas in that it changes from draw to Add. However, such a difference can make Canvas draw more complex graphics, because the objects of Draw are already wrapped circles, rectangles and so on. Add allows you to draw all kinds of weird shapes, and Bezier curves are one of them.

PathMeasure

What is a PathMeasure? Actually, if you focus on the top, we talked about Path, but we still didn’t talk about how to compute a position. In fact, this task is handed over to us by the PathMeasure.

fun init(a){
    pathMeasure = PathMeasure(path, false) pathMeasure? .length.let { pathLength = it mStep = it? .div(INVALIDATE_TIMES) } }override fun onDraw(canvas: Canvas?). {
    super.onDraw(canvas)
    if(pathLength!! >= mDistance!!) { mDistance? .let { pathMeasure? .getPosTan(it, mPos, mTan) } mDistance = mStep? .let { mDistance? .plus(it) } canvas? .drawPoint(mPos? .get(0)!!!!! , mPos? .get(1)!!!!! , paintPoint!!) invalidate() } }Copy the code

The specific code still needs to see the PathView I have completed. Here is a brief introduction. In fact, this PathMeasure calculates the length through Path, and then returns the current Postion and Tan value through the Distance we passed in. In fact, the most common use is an Angle adjustment, if you use a point to display, it does not work, but if it is a Bitmap to reality, there is no Tan value, then our image will not turn the head.

Then redraw the obtained Postion and Tan values, and we can finish our Bezier curve drawing

Scratch card effect actual combat

Now that we know how to draw this image, let’s go further.

First question, what is a scratch card?

Small two picture above!!

Reader: Cool! I want to know how to do this.

Yi: I don’t want to tell you right now, heh heh.

Second question, what are his components?

Masks and underlying images, you might say. But the answer is yes and no. Why is that? If you only have masks and underlying images, this can’t be done completely. You can probably only do the following steps.

A scratch-off card that can only be seen and not scratched, hahahahahahaha!!

Now that we have said that these two are not enough, there must be other components that we need to consider. He was actually a pen, and he actually did the scraping with a pen.

We need to add a few things here.

Off-screen drawing

By writing as follows:

override fun onDraw(canvas: Canvas?). {
    super.onDraw(canvas)
    vallayerId = canvas? .saveLayer(null.null) canvas? .let { canvasIt -> paint? .let {paintIt-> rectBitmap? .let { canvas.drawBitmap(it,0f,0f, paintIt) } paintIt.xfermode = xfermode circleBitmap? .let { canvas.drawBitmap(it,50f, 50f,paintIt) }
            paintIt.xfermode = null} } layerId? .let { canvas.restoreToCount(it) } }Copy the code

Through a short off-screen buffer, to complete the composition of the two layers. This composition is done through a layerId to determine who is family with whom.

Xfermode

Here comes another knowledge point!! How does this work??

Here is a picture to explain, this is Android built-in Xfermode, that is, how the composite mode, you can understand the meaning of the picture, do not have to learn how to calculate, in the final analysis, is to highlight or hide a certain RGB color block.

Okay, with that in mind, let’s get back to business. How do you implement scratch cards? So we know composition, we know off-screen drawing, how do we use it?

Actually, the last thing to talk about is what is a mask? What does the bottom image do?

The bottom image is naturally for us to look at, we can not draw by hand, and then we erase it, so this layer obviously can not be covered by our layer. As for the mask, we need to eliminate the overlap between the image and the path we have traveled by off-screen painting to complete the effect of seeing the image. What mode should this effect be accomplished in? Let’s look at the picture given above, which one is the best.

The scraping process is our Dst and mask is our Src. This is probably XOR. This pattern is the best for our requirements.

But the question anyone who looks at the source code might ask is, why am I creating a DBitmap to do this? This DBitmap is used to limit the size of Paint. It gives Paint a scope and makes it much more comfortable. Of course, if you limit the size of the View in the integrated layout, Filling up exactly can solve this problem, but is not recommended.

Finally, a simple but important point, which Android’s event distribution mechanism always asks, is what method should we override to do the addition of the draw path. It is recommended to do this in OnTouch because OnTouch actually responds before OnTouchEvent.