Android custom controls Series 7: how to measure the size of a widget in the onMeasure () method (I), androidonmeasure
Reprinted please indicate the source: http://blog.csdn.net/cyp331203/article/details/45027641
Methods to override a custom view or viewgroup: onMeasure (), onLayout (), and onDraw (). (If you are not familiar with it, you can view the previous articles in the column:Android custom control series 2: Custom switch button (1)).
Today's task is to study the protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) method in detail.
It is not clear what method is to be rewritten. Go to the source code to see why the onMeasure () method should be rewritten. Where can this method be called:
1. The measure/onMeasure method in the source code:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }
It is actually called in the public final void measure (int widthMeasureSpec, int heightMeasureSpec) method of the View class:
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {...onMeasure(widthMeasureSpec, heightMeasureSpec);...}
1. measure ()
As you can see, the measure () method is a method modified by final, meaning it cannot be overwritten by the quilt class. the role of the measure () method is to measure the actual size of a View, while the Android system does not help us with the actual measurement work, because this work is handed over to onMeasure () so we need to rewrite the onMeasure method as needed when customizing the View. the sub-control is divided into two situations: view and viewGroup. What is the measurement process? You can see the following figure in detail:
2. onMeasure
In onMeasure (int widthMeasureSpec, int heightMeasureSpec), the two parameters are used: widthMeasureSpec and heightMeasureSpec. The two int-type parameters have a relationship between width and height, but they are not actually width and height, but a value synthesized by the corresponding mode in the width, height, and respective directions: among them, in the 32-bit binary bit of the int type, from to 30, the two represent the mode, 0 ~ 29 These thirty bits represent the actual values of width and height. There are three modes, which are defined in an internal class of the View class in Android: View. MeasureSpec:
① UNSPECIFIED: the default value. The parent control does not limit the sub-view. ------ Binary representation: 00
② EXACTLY: indicates that the parent control gives the child view a specific value. The child view should be set to the size of these values. ------ Binary representation: 01
③ AT_MOST: indicates that the child view of the parent control has a specific maximum value, and the Child view cannot exceed this value. ------ Binary representation: 10
Ii. MeasureSpec
MeasureSpe describes the child View Size expectation of the parent View. It contains the Measurement Mode and size. We can extract the mode and size from MeasureSpec using the following method, which uses the Displacement Calculation internally.
Int specMode = MeasureSpec. getMode (measureSpec); // get Mode
Int specSize = MeasureSpec. getSize (measureSpec); // get the size.
You can also use the static method of MeasureSpec to synthesize the size and pattern. This method is just a simple addition.
MeasureSpec. makeMeasureSpec (specSize, specMode );
Each View contains a ViewGroup. layoutParams class or its derived class. LayoutParams contains the relationship between View and its parent View. The size of View is determined by the size of View and its parent View.
We usually use the onMeasure method when adding a view inside RelativeLayout or LinearLayout, whether it is added to the layout file or added using the addView method in the code, the two parameters in measure and onMeasure are passed to the Child control/child view layer by level parent controls. In xml, we can define the specific Layout width and height values or fill methods with width and height: matchparent/wrapcontent, or use LayoutParams settings in code, in fact, the values set here correspond to the modes of the two parameters in the measure and onMeasure methods above. The relationship is as follows:
The specific values (such as width = 200dp) and matchparent/fillparent correspond to the MeasureSpec. EXACTLY
The package content (width = wrapcontent) corresponds to the MeasureSpec. AT_MOST in the mode.
The system calls the measure method. The transfer from the parent control to the heightMeasureSpec of the child control has a set of corresponding judgment rules. The list is as follows:
The width and height of a view can be obtained only after measurement, that is, after the measure method is called. You should have used View. getWidth () and View. getHeight () method. The two methods can return the width and height of the view, but they are not obtained at the beginning. For example, in the oncreate method, at this time, the measure method has not been executed and the measurement has not been completed. We can make a simple experiment: Customize a MyView, inherit the View class, and then in the OnCreate method, add it to the current layout through the addview method. Call the getWidth () and getHeight () Methods of the MyView object and you will find that all the results are 0.
OnMeasure obtains its final size through the size and mode passed by the parent View and the size of its own background image. Then it is set to mMeasuredWidth and mMeasuredHeight through setmeasuredmension.
The onMeasure logic of a common View is similar. It basically measures its content and background, and then determines the final size based on the MeasureSpec passed by the parent View. For example, TextView will determine the size based on the text length, the text size, text line height, text line width, display mode, background image, and the mode and size transmitted by the parent View are determined.
3. onMeasure of ViewGroup
ViewGroup is an abstract class that does not implement onMeasure, but its subclasses have their own implementations. Generally, they use the measureChildWithMargins function or other functions similar to measureChild to traverse the measurement subview, the child View of GONE does not participate in the measurement. After all the child views are measured, the size of the Child View is determined based on the mode and size passed by the parent View.
When measuring a sub-View, the LayoutParams of the sub-View is obtained first, and the width and height are obtained from the sub-View. If the value is greater than 0, the sub-View is passed in a precise mode and the value is combined into MeasureSpec, if it is less than 0, it will pass its own size or remaining size to the subview, and its mode determines that there is a ing relationship in the preceding table.
ViewGroup generally calls setMeasuredDimension () to set its own size after measuring all child views, as shown in the first figure.
It may be clear that the Android system still does not understand the specific method for passing parameters through measure and onmeasure. Before studying this issue, let's take a look at the simplest helloworld UI hierarchical relationship diagram:
For convenience, here we use requestWindowFeature (Window. FEATURE_NO_TITLE); remove the influence of the title bar and only view the hierarchical relationship.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="${relativePackage}.${activityClass}" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /></RelativeLayout>
package com.example.hello;import android.app.Activity;import android.os.Bundle;import android.view.Window;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);}}
UI hierarchical relationship diagram:
We can find that the simplest hierarchical relationship graph of helloworld is like this. It was initially a PhoneWindow internal class DecorView, which is actually a viewGroup at the bottom layer loaded by the system, it is a subclass of FrameLayout, then loads a LinearLayout, and then loads a FrameLayout with content id and a ViewStub on this LinearLayout. This is actually the original location of the ActionBar, because we use requestWindowFeature (Window. FEATURE_NO_TITLE) is changed to an empty ViewStub, and then the RelativeLayout and TextView written in our layout XML file are loaded in FrameLayout with the id of content.
Then, the measure method must transfer the size and mode in the system from the DecorView layer. We assume that the mobile phone screen is 320*480, in this case, DecorView first reads the cell phone size from the hardware configuration file, and then sets the measure parameter size to 320*480, while the mode is EXCACTLY. The transmission relationship can be indicated:
Well, the principle will be here. The next article will show how to use onMeasure to measure a custom ImageView so that it can automatically fill the screen width and measure the height through measure, adaptive height adjustment never causes stretching/compression deformation. Please pay attention to it. Thank you.
Reprinted please indicate the source: http://blog.csdn.net/cyp331203/article/details/45027641