Android Onmeasure and OnLayout and Measurespec secrets

Source: Internet
Author: User

The most important thing about customizing ViewGroup in Android is the Onmeasure and OnLayout methods, both of which need to be rewritten, and the process of ViewGroup painting is like this: Onmeasure→onlayout→dispatchdraw

[Java]View Plaincopy
    1. In fact, I think the Official document interpretation has a big problem, just beginning has been very puzzled onmeasure and onlayout what meaning, read a lot of information after the enlightened, summarized as follows

The first thing to know is that ViewGroup is inherited from view, and the explanation behind it is about view. Viewgourp can contain a lot of View,view is its child, such as LinearLayout layout is a viewgroup, in the layout can put TextEdit, imageview and so on commonly used controls, these are called sub-view, Of course not limited to this fixed control.

Onmeasure→onlayout→dispatchdraw:onmeasure is responsible for measuring the size of this viewgroup and sub-view, OnLayout is responsible for setting the sub-view layout, Dispatchdraw is really painted up.

onmeasure

Official explanation:

protected void onmeasure (int widthmeasurespec, int heightmeasurespec) Measure The view and its content to determine the measured width and the measured height. That is, the measurement view and its contents determine the width and height. to tell the truth, the official document said the measurement I was just beginning very puzzled, onmeasure translation is measured, do not know its intentions, in fact, it has two functions: ① get ViewGroup and sub-view width and height ② set sub-viewgroup width and height, attention, just width and height. In fact, the trace Onmeasure method will find that it inherits from view. an implementation of the typical onmeasure [Java]View Plaincopy
  1. @Override
  2. protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
  3. int width = measurespec.getsize (widthmeasurespec); //Get viewgroup width
  4. int height = measurespec.getsize (heightmeasurespec); //Get viewgroup height
  5. Setmeasureddimension (width, height); //Set the width of the ViewGroup
  6. int childCount = Getchildcount (); ///Get the number of child view, traverse these sub-view settings below to set the width height
  7. For (int i = 0; i < ChildCount; i++) {
  8. View child = Getchildat (i);
  9. Child.measure (Viewwidth, viewheight); //Set sub view width height
  10. }
  11. }
It's obvious that you get the width and height reset first. The order is to set the ViewGroup first, and then set the child view.wherein, the method of setting ViewGroup width is setmeasuredimension (), view the source code of this method, it is under View.class [Java]View Plaincopy
  1. Protected final void setmeasureddimension (int measuredwidth, int measuredheight) {
  2. Boolean optical = islayoutmodeoptical (this);
  3. if (Optical! = islayoutmodeoptical (mparent)) {
  4. Insets Insets = Getopticalinsets ();
  5. int opticalwidth = Insets.left + insets.right;
  6. int opticalheight = insets.top + insets.bottom;
  7. Measuredwidth + = optical? Opticalwidth:-opticalwidth;
  8. Measuredheight + = optical? Opticalheight:-opticalheight;
  9. }
  10. Mmeasuredwidth = Measuredwidth; //This is the Save to class variable
  11. Mmeasuredheight = Measuredheight;
  12. Mprivateflags |= Pflag_measured_dimension_set;
  13. }
The Setmeasuredimension method must be called by Onmeasure, and the code above is just called in Onmeasure, so it meets the requirements. Where is this wide-height setting stored? As can be seen in the source code, it is stored in ViewGroup: Mmeasuredwidth,mmeasuredheight is a variable in the view class.Next is to set the height of the sub-view, each sub-view will be set separately, the width of course is defined by itself. Child.measure (Viewwidth, viewheight); Call the measure method, notice that this method is a method of sub-view, where is the height of the setting stored? By the way, it is in each of the sub-view, not in the viewgroup, that this should be clear. and look at the realization of measure [Java]View Plaincopy
  1. Public final void measure (int widthmeasurespec, int heightmeasurespec) {
  2. <span style="White-space:pre" > </span>, ... ..
  3. <span style="White-space:pre" > </span>//measure ourselves, this should set the measured dimension FL Ag back
  4. Onmeasure (Widthmeasurespec, Heightmeasurespec);
  5. <span style="White-space:pre" > </span>, ... ..
  6. }
In fact, it calls the Onmeasure method in the view class, and looks at the Onmeasure method of View.class. [Java]View Plaincopy
    1. protected void  onmeasure (int widthmeasurespec, int  HEIGHTMEASURESPEC)  {    
    2.          setmeasureddimension (Getdefaultsize (Getsuggestedminimumwidth (),  widthMeasureSpec) ,     
    3.                  getdefaultsize (Getsuggestedminimumheight (),  heightMeasureSpec));     
    4. }  
It's strange, and back to the original Setmeasuredimension method, in the final analysis, the real set ViewGroup and sub-view width is Setmeasuredimension method, but why the above child.measure ( Viewwidth, viewheight); not directly call Child.setmeasuredimension (Viewwidth,viewheight), how convenient ah. Because Setmeasuredimension () can only be called by the Onmeasure () method. So onmeasure is nothing magical about measuring (Measure) and setting (determine) wide, now finally understanding the API documentation explained. OnLayoutOfficial explanations protected abstract void OnLayout (Boolean changed, int l, int t, int r, int b) called from layout when this view Shoul D Assign a size and position to all of its children. It is the size and position of the set child view. Onmeasure just get wide and store in its own view, then ViewGroup don't know the size of the child view at all, OnLayout tell ViewGroup, the size of the child view inside it and where to put it. Notice the difference of two, I was also confused. parameter int l, int t, int r, int b Needless to say, is the position of viewgroup on the screen. [Java]View Plaincopy
  1. @Override
  2. protected void OnLayout (boolean changed, int left, int top, int. right, int bottom) {
  3. int mtotalheight = 0;
  4. //Of course, also traverse the sub view, each to tell ViewGroup
  5. int childCount = Getchildcount ();
  6. For (int i = 0; i < ChildCount; i++) {
  7. View Childview = Getchildat (i);
  8. //Get the View dimensions calculated in Onmeasure
  9. int measureheight = Childview.getmeasuredheight ();
  10. int measuredwidth = Childview.getmeasuredwidth ();
  11. Childview.layout (left, Mtotalheight, Measuredwidth, Mtotalheight + measureheight);
  12. Mtotalheight + = Measureheight;
  13. }
  14. }
Next is Dispatchdraw ... Well, now the understanding can only be like this ADD: about the MeasurespecMeasurespec is an inner class in view, a measurespec encapsulates the layout requirements passed from parent to child. The parameter that encapsulates the layout pass. It stands for height and width, first with a usage code: [Java]View Plaincopy
  1. @Override
  2. protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
  3. super.onmeasure (Widthmeasurespec, Heightmeasurespec);
  4. int width = measurespec.getsize (widthmeasurespec); //Get real width
  5. int height = measurespec.getsize (heightmeasurespec); //Get real height
  6. Setmeasureddimension (width, height); //Set the width of the ViewGroup
  7. For (int i = 0; i < Getchildcount (); i++) {
  8. Getchildat (i). Measure (Widthmeasurespec, heightmeasurespec); //Traverse child set wide height
  9. }
  10. }
Why Onmeasure parameters Widthmeasurespec and heightmeasure to go through the GetSize () method to get the true width, since the parameter is an int type why does not directly convey the true width of the high, in fact, this hidden mystery. Of course we directly find the source of Measurespec. [Java]View Plaincopy
  1. Public static class Measurespec {
  2. private static final int mode_shift = 30; //    
  3. private static final int mode_mask = 0x3 << mode_shift;
  4. public static int getmode (int measurespec) {
  5. return (Measurespec & Mode_mask);
  6. }
  7. public static int getsize (int measurespec) {
  8. return (Measurespec & ~mode_mask);
  9. }
  10. }
Looking at the GetSize method, he uses the arguments passed in to parse it. In fact, the direct view will be very faint, basically unintelligible, so look back Onmeasure method, Debug Onmeasure method, inside the Widthmeasurespec, Heightmeasurespec and parse out the value of width, The value of height is as follows:
Found before and after the value difference is very far, and then combined with the source code Widthmeasurespec & ~ Mode_mask, after the operation just match to get width. Operation Method: 0x3=0011, it shifts 30 bits to the left, gets 1100 0000 ... (1 after a total of 30 0.) ~ After the reverse is 0011 1111 ... (0 followed by 30 1). The above widthmeasurespec is 1073742304, converted to binary is 0100 0000 0000 0000 0000 0001 1110 0000, and the front of that ~mode_mask & (Note MoD E_mask to first take the reverse and widthmeasurespec), the front of the 2 1 is removed, Widthmeasurespec only left behind a section of 1, that is to get 0000 ... (omit 16 x 0) ... 0001 1110 0000, the resulting value is converted to decimal exactly 480, perfect, converted to get the true width. The phone's screen is just 480*854, which is the Xiaomi 1 screen. Ps: But why bother so much? Why shift to left shift 30? Look closely at the GetMode () method, which is also used and getsize () the same parameters to parse, in fact getsize just used a portion of the Measurespec to represent the width or height, the remaining high to represent the value of GetMode. And look at the value of Widthmeasurespec, it left up to two bits is 01, then and Mode_mask & After, get 0100 ... (Save 30 0 after 1), or 0x40000000, to view several constants in Measurespec: At_most = 0x80000000
exactly = 0x40000000
upspecified = 0x00000000GetMode after parsing, get exactily. So say a measurespec parameter to get two values, one is the specific size value, one is the value of the pattern, and then look at the official document explanation, finally understand why called encapsulates, have to say Google Engineer Cow. We usually use the XML layout in the Layout_width or layout_height can specify two values, one is specific, such as 100DP, one is math_parent and the like, is encapsulated here ... Corresponds to two values Oh ~ back to the previous why to move left 30-bit problem. Because the int type is 32 bits, the original value 0x3 30 bits after the left shift and uses the highest two bits to represent the mode value, and when we pass the MEASURESPEC is a positive number, we do not use the highest two digits to represent the real value getsize to parse. That is, even if the true value is used to 3221225471, the true value can be parsed correctly without worrying that the real value will overflow. There is no screen of that big resolution on the Earth! But this is my personal guess.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.