• A list,

Android is drawn in order, the content drawn first will be covered by the content drawn later, and There are many methods of drawing in Android. OnDraw (), dispatchDraw(), onDrawForeground(), draw() methods also play a key role in the drawing sequence. This paper mainly introduces some of the functions of these methods in the drawing sequence

  • Second, the key method

  • onDraw()

1. OnDraw ()

OnDraw () is the most commonly used rewriting method in the drawing process, by rewriting onDraw() method can draw a number of different shapes of graphics, text, example below

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        var drawable = drawable
        if(BuildConfig.DEBUG && drawable! =null){ canvas? .save() canvas? .concat(imageMatrix) var bounds = drawable.bounds canvas? .drawText(resources.getString(R.string.image_size,bounds.width(),bounds.height()),20f,40f,paint) canvas? .restore() } }Copy the code

2, Do we place some of our draw code before or after super.ondraw ()?

Before super.ondraw () :

Because the drawn code is called before the original control is drawn, the drawn content is obscured by the original control’s drawn content. Here is an example of a TextView with a background color. Since super.ondraw () has already drawn the color, some text will have a background color, eg:

override fun onDraw(canvas: Canvas?) { var layout = layout bounds.left = layout.getLineLeft(0) bounds.right = layout.getLineRight(0) bounds.top = layout.getLineTop(0).toFloat() bounds.bottom = layout.getLineBottom(0).toFloat() canvas? .drawRect(bounds,paint) super.onDraw(canvas) }Copy the code

After super.ondraw () :

Because the drawing code is executed after the original content is drawn, the drawn content overwrites the original content of the control. This example shows a demo that prints the size of an image in the ImageView control.

//draw() is the overall scheduling method for the drawing process. The entire drawing process of a View takes place in the draw() method. The background, body, subview, slide correlation, and foreground are all drawn in the draw() method. override fun draw(canvas: Canvas?) {super.draw(canvas) // Insert the drawing code below super.draw() so that the drawing content covers all other paints.color = color.parsecolor ("#f44336") canvas? .drawRect(0f, 40f, 200f, 120f, paint) paint.color = Color.WHITE canvas? .drawText("New", 20f, 100f, paint)

    }
Copy the code

  • dispatchDraw()

1, dispatchDraw() method introduction:

Method that is called after the child view has been drawn. You can override this method to overwrite the content you draw on the child view. Otherwise, the content drawn by the parent control is overwritten by the quilt control

override fun onDraw(canvas: Canvas?) {super.ondraw (canvas) // Insert drawing code below super.ondraw (), draw some drawPoint(canvas = canvas)}Copy the code
<? xml version="1.0" encoding="utf-8"? > <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
>
    <com.zy.draworder.AfterDispatchDrawView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

    <ImageView
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:src="@drawable/logo"
    />
    </com.zy.draworder.AfterDispatchDrawView>
</FrameLayout>
Copy the code

Do we place some of our draw code before or after super.dispatchdraw ()?

Before super.dispatchdraw () :

Write the draw code above super.dispatchdraw () and the draw will occur after the onDraw() of the child view and before super.dispatchdraw (), meaning the draw will appear between the main content and the child view.

// Place the drawing code above super.dispatchdraw () and the drawing will take place after onDraw() and before super.dispatchdraw (), i.e. the drawing will take place between the main content and the sub-view. override fun dispatchDraw(canvas: Canvas?) { drawPoint(canvas = canvas) super.dispatchDraw(canvas) } fun drawPoint(canvas: Canvas?) { paint.color = Color.GREEN canvas? DrawCircle (width * 0.1f,height * 0.1f,55f,paint) canvas? DrawCircle (width * 0.2f,height * 0.2f,15f,paint) canvas? DrawCircle (width * 0.3f,height * 0.3f,15f,paint) canvas? DrawCircle (width * 0.4f,height * 0.4f,15f,paint) canvas? DrawCircle (width * 0.5f,height * 0.5f,15f,paint) paint. DrawCircle (width * 0.9f,height * 0.1f,55f,paint) canvas? DrawCircle (width * 0.8f,height * 0.2f,15f,paint) canvas? DrawCircle (width * 0.7f,height * 0.3f,15f,paint) canvas? DrawCircle (width * 0.6f,height * 0.4f,15f,paint) paint. Shader = RadialGradient(width * 0.1f,height * 0.1 f, f, 55 Color. ParseColor ("#E91E63"),
            Color.parseColor("#2196F3"), Shader.TileMode.CLAMP) canvas? . DrawCircle (width * 0.5f,height * 0.5f,55f,paint)}Copy the code

After super.dispatchdraw () :

Place the drawing code under super.dispatchdraw (), and the drawing will take place after the onDraw() of the child view and after the super.dispatchdraw () of the child view. So it covers the child View.

// Just override dispatchDraw() and write your draw code under super.dispatchdraw (). The draw code will happen after the child View is drawn, so that the drawing content will cover the child View. override fun dispatchDraw(canvas: Canvas?) { super.dispatchDraw(canvas) drawPoint(canvas = canvas) } fun drawPoint(canvas: Canvas?) { paint.color = Color.GREEN canvas? DrawCircle (width * 0.1f,height * 0.1f,55f,paint) canvas? DrawCircle (width * 0.2f,height * 0.2f,15f,paint) canvas? DrawCircle (width * 0.3f,height * 0.3f,15f,paint) canvas? DrawCircle (width * 0.4f,height * 0.4f,15f,paint) canvas? DrawCircle (width * 0.5f,height * 0.5f,15f,paint) paint. DrawCircle (width * 0.9f,height * 0.1f,55f,paint) canvas? DrawCircle (width * 0.8f,height * 0.2f,15f,paint) canvas? DrawCircle (width * 0.7f,height * 0.3f,15f,paint) canvas? DrawCircle (width * 0.6f,height * 0.4f,15f,paint) paint. Shader = RadialGradient(width * 0.1f,height * 0.1 f, f, 55 Color. ParseColor ("#E91E63"),
            Color.parseColor("#2196F3"), Shader.TileMode.CLAMP) canvas? . DrawCircle (width * 0.5f,height * 0.5f,55f,paint)}Copy the code

  • onDrawForeground()

1, onDrawForeground() method

This method was only introduced in API 23, so make sure your minSdk is up to 23 before rewriting this method, otherwise your software will not work on a lower version of the phone. In onDrawForeground(), slide edge gradient, slider bar, and foreground are drawn in sequence. So if you overwrite onDrawForeground()

2, Do we get some code of draw before super.onDrawForeground() or after it?

Place before super.ondrawforeground () :

If you use super.ondrawforeground (), the drawing will be executed between dispatchDraw() and super.ondrawforeground (), and will cover the subview, But covered by sliding edge gradients, sliders, and foreground:

    override fun onDrawForeground(canvas: Canvas?) {
        paint.color = Color.parseColor("#f44336") canvas? .drawRect(0f, 40f, 200f, 120f, paint) paint.color = Color.WHITE canvas? .drawText("Foreground", 20f, 100f, paint)
        super.onDrawForeground(canvas)
    }
Copy the code

Place after super.ondrawforeground () :

If you write the draw code below super.ondrawforeground (), the draw code will be executed after the slide edge gradient, slider, and foreground, which will cover the slide edge gradient, slider, and foreground.

override fun onDrawForeground(canvas: Canvas?) Paint. Color = color.parsecolor (> super.ondrawforeground (canvas) > super.ondrawforeground (canvas)"#f44336") canvas? .drawRect(0f, 40f, 200f, 120f, paint) paint.color = Color.WHITE canvas? .drawText("Foreground", 20f, 100f, paint)
    }
Copy the code

  • draw()

1. Draw ()

Draw () is the overall scheduling method for the drawing process. The entire drawing process of a View takes place in the draw() method. The background, body, subview, slide correlation, and foreground are all drawn in the draw() method.

public void draw(Canvas canvas) { ... drawBackground(Canvas); // Draw background (cannot be overridden) onDraw(Canvas); // Draw the main dispatchDraw(Canvas); // Draw child View onDrawForeground(Canvas); // Draw slide correlation and foreground... }Copy the code

2, Do we put some code in draw before or after super.draw()?

Put it before super.draw() :

Since draw() is the master scheduling method, if you write the draw code above super.draw(), it will be executed before all the other draws, so that part of the draw will be overwritten by everything else, including the background. Yeah, the background will cover it, too.

override fun draw(canvas: Canvas?) {// Draw () is the master scheduling method, so if you write the draw code above super.draw(), it will be executed before all the other draws, so that part of the draw will be covered by everything else, including the background. Yeah, the background will cover it, too. canvas? .drawColor(Color.parseColor("#00BB6A")); // Draw a green super.draw(canvas)}Copy the code

After super.draw() :

Since draw() is the master scheduling method, if you write your draw code below super.draw(), it will be executed after all other draws are completed, that is, its draw will override all other draws.

It has the same effect as overriding onDrawForeground() and putting the drawing code under super.ondrawforeground () : it overpowers everything else.

override fun draw(canvas: Canvas?) {super.draw(canvas) // Insert the drawing code below super.draw() so that the drawing content covers all other paints.color = color.parsecolor ("#f44336") canvas? .drawRect(0f, 40f, 200f, 120f, paint) paint.color = Color.WHITE canvas? .drawText("New", 20f, 100f, paint)
    }
Copy the code

  • Conclusion:

1. It is very important to know how to draw order, especially when a custom view has child views, and when you want to do some operations in the foreground background, pay attention to the relationship between it and the super.xx() call

2. For efficiency reasons, ViewGroup bypasses draw() by default and executes dispatchDraw() instead to simplify the drawing process. So if you customize a ViewGroup subclass (such as LinearLayout) and need to draw inside any of its draw methods other than dispatchDraw(), You may need to call the view.setwillNotDraw (false) line to switch to the full drawing process. (This is possible, not necessary, because some viewgroups already call setWillNotDraw(false). For example, ScrollView.

3. Sometimes, the same drawing code will look the same in different drawing methods. You can choose a drawing method you like or are used to. There is one exception: if the drawing code can be written in either onDraw() or another drawing method, it should be written in onDraw() first, because Android has optimizations that automatically skip onDraw() when redrawing is not required to improve development efficiency. The only method that enjoys this optimization is onDraw().