Summary of the use and principle of Android custom view

In Android development, the UI controls provided by the system are limited. When we need to use some special controls, relying only on the controls provided by the system may not achieve the effect we want. At this time, we need to customize some controls to complete the effect we want. Next, let me talk about those things about custom controls.

First, let me talk about the control architecture of Android. Android controls can be divided into two categories: ViewGroup and view. You can include multiple views in a ViewGroup and manage them. The control tree is composed of these two parts. The upper layer of the control tree is responsible for the drawing, measurement and interaction of the lower controls. The findviewbyid () method we use in the activity is to search the corresponding ID in the control tree by depth traversal. At the top of each control tree, there is a viewparent object. It is the core of the whole tree and is responsible for scheduling all interactive events. In the activity, we use setcontentview () to load the layout. Each activity contains a window object, usually phonewindow in Android. It takes a decorview as the root view of the whole window and presents the content to be displayed on the window. Decorview is divided into two parts: titleview and contentview. Contentview is a FrameLayout with ID content, and the layout file is set in it. Titleview is the title bar of the topbar we see. This is how the activity loads the layout file.

Next, let's talk about the use of custom controls. The following explanation will be accompanied by some principle analysis. Custom controls can be divided into three types. One is to expand the system controls provided by Google to achieve the desired effect. One is to combine the controls provided by the system and use them as a combined control. Another is to redraw the measurement with a new control.

1、 Expand system controls provided by Google

If we want to expand the textview control, first we need to define a class to inherit textview and selectively override its ondraw(), onmeasure(), ontouchevent() and other methods. Among them, ondraw() is responsible for drawing the image, onmeasure() is responsible for measuring the position, and ontouchevent() is responsible for setting the touch event. When we want to directly draw a textview with background color, we can define a brush in the class and draw it in ondraw(). The code is as follows:

Paint paint1=new Paint(); //定义画笔
paint1.setColor(Color.YELLOW);
paint1.setStyle(Paint.Style.FILL);

Then, through the following code, you can draw a textview with a rectangular box, but you need to call OnDraw () of the parent class after drawing. Because it is extended on the system control, it also has its original function.

@Override
  protected void onDraw(Canvas canvas) {
    canvas.drawRect(0,getMeasuredWidth(),getMeasuredHeight(),paint1);//绘制矩形
    canvas.save();
    super.onDraw(canvas);
    canvas.restore();
  }

The canvas object can be used for drawing. I will explain the canvas in the next blog.

Then, we only need to add custom controls to the layout file. In the layout file, the name of the custom view is the package name of the custom control class plus the class name. Suppose that the custom textview class is defined to inherit textview, as shown in the following example:

<com.example.myapplication.View.CustomTextView
    android:layout_width="wrap_content"
    android:layout_height="match_parent"></com.example.myapplication.View.Buttonbtn>

2、 Group the controls provided by the system together

In addition to expanding the original control, we can also combine the control into a new control. First, we define a new layout file and add ImageView and textview. The code is as follows.

<ImageView
  android:id="@+id/iv"
  android:layout_width="20dp"
  android:layout_height="20dp"
  android:src="@mipmap/ic_launcher" />

<TextView
  android:id="@+id/tv"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_marginTop="2dp"
  android:text="消息"
  android:textSize="13sp" />

Then we define a class that inherits LinearLayout and initializes the control and layout in the class's construction method.

public void init(Context context) {
    //指定线性布局的显示方式,垂直
    setOrientation(VERTICAL);
    //设置用户期望的布局方式
    LayoutParams mLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
    setLayoutParams(mLayoutParams);
    setGravity(Gravity.CENTER);
    setPadding(4,4,4);
    //设置其布局文件
    View mButtonbtnView = LayoutInflater.from(context).inflate(layout.botton_btn_view,this,true);
    mImageView = mButtonbtnView.findViewById(id.iv);
    mTextView = mButtonbtnView.findViewById(id.tv);
  }

Next, its use method is the same as that of expanding controls. You can add controls directly to the layout file.

<com.example.myapplication.View.Buttonbtn
    android:layout_width="wrap_content"
    android:layout_height="match_parent"></com.example.myapplication.View.Buttonbtn>

3、 Override view to implement a new control

When the system's native controls can't meet our needs, we can define a new control to complete the required functions. To create a new control, you need to inherit the view class. The difficulty is mainly to draw the control and realize interaction. When inheriting the view class, we also need to override its ondraw(), onmeasure(), ontouchevent() to implement drawing, measuring and touching events.

Ondraw() drawing is to use a series of methods to draw the canvas object and draw the shape of the control.

onMeasure()

Next, let me talk about onmeasure (). Before drawing a view, we need to tell the system how large a view we need to draw and its location. This is what onmeasure () does. First, let's understand the three modes of measurement:

Exact: exact value mode, which will be used when specifying the specific value of view.

AT_ Most: maximum value mode. It is used when the control is set to "wrap_content". It will change according to the change of child control or content.

Unspecified: the drawing control can be as large as it wants.

According to the above three modes, we can judge and use them during measurement. First, we rewrite the onmeasure () method of a view. Then obtain the measurement mode of the control by using the measurespec class. Measurespec uses bit operation. The upper 2 bits are the measurement mode, and the remaining 30 bits are the measurement size.

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

    if (widthMode == MeasureSpec.EXACTLY) {

    } else if (widthMode == MeasureSpec.AT_MOST) {

    } else if (widthMode == MeasureSpec.UNSPECIFIED) {

    }

  }

The above code defines the size of the control by judging the measurement mode. Here, only the width of the control is measured, and the measurement of the height of the control is similar, so I won't explain it in detail.

As mentioned earlier, ViewGroup is used to manage controls. When the size of ViewGroup is "wrap_content", it will traverse all its child views to obtain the size of child views, and then set its own size. The layouts we have used, such as relativelayout and LinearLayout, inherit ViewGroup, so they also use this method to obtain their own size.

onTouchEvent()

Ontouchevent () is what we call a touch event. Because Android phones are touch-screen, we also need some processing to complete the interaction when we customize the view to touch the screen. When overriding the ontouchevent method, we can see the object that needs to be passed in motionevent. We can use this class to set the touch event and get the position of the touch point. We can get the action of the touch event through getaction () to judge whether to press the screen or move. In the Android coordinate system, we all know that when the Android screen is on the vertical screen, the position in the upper left corner is the origin, the right is the positive direction of the X axis, and the down is the positive direction of the Y axis. After knowing this, we can obtain the coordinates of the touch point by calling getx() and gety() methods to complete some interactive operations.

public boolean onTouchEvent(MotionEvent event) {
    float x;
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
      {
        x=event.getX();
      }
        break;
      case MotionEvent.ACTION_MOVE:
        break;
      case MotionEvent.ACTION_UP:
        break;
    }
    return true;
  }

The above are the common rewriting methods of custom controls. By rewriting these methods, we can basically implement a simple custom control. Next, let's understand the principle of the event interception mechanism of the lower control.

Analysis of event interception mechanism

As we mentioned earlier, the control structure is a tree structure, and there may be multiple viewgroups or views in a ViewGroup. How can touch events be accurately assigned to each view and ViewGroup. Let's assume that there is a viewgroupa with viewgroupb nested inside, and a view nested inside viewgroupb. When we override the viewgroupa class, we need to override these three methods:

When overriding the view, you need to override two methods:

According to the name, there is more onintercepttouchevent () method in ViewGroup than in view, which is the core of event interception. In each method, click log and then click view to find the sequence of method calls:

First, the dispatchtouchevent () and onintercepttouchevent () of the viewgroupa class are called.

Then called the dispatchtouchevent () and onintercepttouchevent () of the viewgroupb class.

Then go to the dispatchtouchevent () method of view.

The sequence of this call is the sequence of event delivery, and the sequence of event processing is:

From this, we can see that the event distribution is published by the upper ViewGroup, and then distributed layer by layer. The event is processed by the lower level view and then uploaded layer by layer. As mentioned earlier, onintercepttouchevent() is the core of event interception. Then, as long as its return value is set to true, the event can be intercepted and no longer distributed. While ontouchevent() returns false, and the event will not be uploaded after processing. The process of event distribution and interception is roughly explained.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>