preface

View, there’s a lot of names. Whether you’re familiar with the layout or the controls, they all inherit from the View.

Some of the images in this article are reprinted from an article by Carson_Ho

Mind mapping

The working process

measure

We already know how to calculate the size of the control in the second layout image.

  • height = bottomtop
  • width = rightleft

In the case of a ViewGroup, this is traversal and evaluation of the child controls in the container.

Because controls that inherit directly from a View use wrap_cotent and match_parent, they display the same effect. We need to use the getMode() method in MeasureSpec to differentiate and compare the current patterns.

model state
UNSPECIFIED The mode is not specified, the View can be as large as it wants, the parent container is not limited, generally used for internal system measurement
AT_MOST Maximum mode, corresponding to WRAP_content, View size is not larger than the value of SpecSize
EXACTLY Exact mode, corresponding to match_parent, View size is the value of SpecSize
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // Used to get the set mode
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        // Get the set length
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        // Such judgments will not be repeated much later
        // is used to determine whether it is wrap_content
        // If left untreated, the effect will be match_parent
        if(widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(20.20); }}Copy the code

layout

In determining position, we have a major need for the coordinate system. The Android system’s coordinate system is not the same as the normal drawing coordinate system.

So correspondingly, our calculation of position is, of course, the exact opposite of what we had before.

The positions of the four vertices are determined by four values:

  • Top: The distance between the top edge of the child View and the top edge of its container.
  • Left: The distance between the left edge of the child View and the left edge of its container.
  • Bottom: The distance between the bottom edge of the child View and the top edge of its container.
  • Right: The distance from the right edge of the child View to the left edge of its container.

All calculations are performed relative to the container in which they are performed.

draw

There are 6 steps:

  1. If necessary, draw the background — drawBackground(canvas);
  2. Save the current Canvas layer — saveCount = Canvas.getSavecount ();
  3. Draw the contents of the View — if (! dirtyOpaque) onDraw(canvas);
  4. Draw sub-view — dispatchDraw(canvas);
  5. If needed, draw a faded edge of the View, similar to a shadow effect — Canvas.restoreToCount (saveCount);
  6. Draw decorations, such as the scroll bar — onDrawForeground(canvas);

The general method developers need to rewrite is the third step to draw the View’s contents corresponding to onDraw().

    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();
        // Do something like this on the canvas
        canvas.drawLine(0, height/2, width,height/2, paint);
    }
Copy the code

Getting started with customizing views

We often in the daily project layout file using the XMLNS: app = “http://schemas.android.com/apk/res-auto” this label, actually he is used to introduce our custom tags to use.

  1. inres/valuesDirectory creationattrs
<?xml version="1.0" encoding="utf-8"? >
<resources>
    <declare-styleable name="DefaultView">
        <attr name="color" format="color"/>
    </declare-styleable>
</resources>
Copy the code
  1. inDefaultView(Context context, @Nullable AttributeSet attrs)In the acquisition. Here is the complete code.
/** * author: ClericYi * time: 2020-01-30 */
public class DefaultView extends View {
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private int mColor = Color.RED;

    public DefaultView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initAttrs(context, attrs);
        initDraw();
    }

    private void initAttrs(Context context, @Nullable AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DefaultView);
        // The name obtained from styleable is generated by the system, usually in the form of class name _name
        mColor = array.getColor(R.styleable.DefaultView_color, Color.GREEN);
        // Recycle the resource after obtaining it
        array.recycle();
    }

    private void initDraw(a) {
        paint.setColor(mColor);
        paint.setStrokeWidth(3f);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();
        canvas.drawLine(0, height/2, width,height/2, paint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if(widthMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(20.20); }}}Copy the code

Basic performance optimization

First of all, how do we know oneViewIs it overdrawn?

This option already exists in development mode on our phones.

Before the opening After the opening

The corresponding graph of times is shown below

So how do you optimize performance?

Before we get to that question, we need to understand what overdrawing is, which you can think of as useless data created by overlaying controls in the same location over and over again. Let’s talk about centralized solutions.

Scheme 1: Reduce the number of nesting layers.

Use a linear layout Using constraint layouts

ConstraintLayout because it does not repeat itself in the same area. The result of a nested LinearLayout implementation is that it can be implemented directly with a ConstraintLayout

Option 2: Remove the default background

This solution addresses the problem that the background will be automatically drawn, and if we remove this layer, it will be an improvement from the drawing point of view. As shown in the diagram, the layer is reduced directly.

Specific representation in code, through thestyle.xmlIn theThemeModify:

<item name="android:windowBackground">@null</item>
Copy the code

conclusion

The above is my learning results, if there is anything I did not think about or there is a mistake in the article, welcome to share with me.


Related articles recommended:

What else do you know about the application layer besides HTTP?

What do you know about the TCP layer?

Android must know will be four components — ContentProvider