preface

  • When customizing a View, use getMeasuredWidth()/getMeasuredHeight() or getWidth()/getHeight() to get the width/height of the View, but what’s the difference?
  • Today, I will dig into the source code to analyze the differences between the two, and I hope you will enjoy it.

directory


1. GetMeasuredWidth ()/getMeasuredHeight () returns the value

1.1 the conclusion

The value returned is the width/height measured by the View during the Measure process

1.2 Source Code Analysis

  • Since getMeasuredWidth() is the same as getMeasuredHeight(), only getMeasuredWidth() will be covered below
  • The process of customizing a View is called a Measure process. The process of customizing a View is called a Measure process.
public final int getMeasuredWidth() { return mMeasuredWidth & MEASURED_SIZE_MASK; Measuredwidth () returns mMeasuredWidth (MEASURED_SIZE_MASK = static constant = limit mMeasuredWidth) Measure process setMeasuredDimension() -> Analysis 1 //} /** * Analysis 1: setMeasuredDimension() **/ protected final void setMeasuredDimension(int measuredWidth, Int measuredHeight (measuredHeight) {measuredHeight (measuredHeight) {measuredHeight (measuredHeight); MeasuredWidth = measuredWidth mMeasuredWidth = measuredWidth; // If measuredWidth = measuredWidth mMeasuredWidth = measuredWidth; mMeasuredHeight = measuredHeight; mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; } // setMeasuredDimension () parameter measuredWidth is obtained from getDefaultSize() // called in onMeasure () -> Analysis 2 /** * Analysis 2: onMeasure () * a. Calculate the width/height of the View according to the measurement specification: getDefaultSize() * b. Store measured View width/height: SetMeasuredDimension () **/ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension() **/ protected void onMeasure(int widthMeasureSpec, int HeightMeasure) { View width/height measurement specification // Pay special attention to this sentence, GetDefaultSize (suggestedMinimumWidth (), widthMeasureSpec) setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec) getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); } /** * analysis 3: getDefaultSize() * **/ public static int getDefaultSize(int size, int measureSpec) {// // measureSpec: measureSpec // int result = size; Int specMode = MeasureSpec. GetMode (MeasureSpec); int specSize = MeasureSpec.getSize(measureSpec); Switch (specMode) {// With UNSPECIFIED mode, the provided default Size = parameter Size Case MeasureSpec.UNSPECIFIED: result = Size; break; // Size case measureSpec.AT_MOST: Case measureSpec.EXACTLY: result = specSize; break; } // Return View width/height value return result; }Copy the code

2. GetWidth ()/getHeight () returns a value

2.1 the conclusion

The value returned is the width/height of the View during the Layout process, which is the final width/height

2.2 Source Code Analysis

  • Since getWidth() is the same as getHeight(), only getWidth() is explained below.
  • Please be sure to understand the custom View Layout process: custom View Layout process – the most understandable custom View principle series (3)
public final int getWidth() { return mRight - mLeft; SetFrame () -> analysis 1} /** * analysis 1: setFrame () * set the position of the View according to the four positions passed in. */ protected Boolean setFrame(int left, int top, int right, int bottom) {... MLeft = left; mLeft = left; mLeft = left; mTop = top; mRight = right; mBottom = bottom; // The setFrame () arguments left and right are passed in from the layout () call -> analysis 2} /** * Analysis 2: layout () * Public void layout(int l, int t, int r, int b) {... public void layout(int l, int t, int r, int b) {... Boolean changed = isLayoutModeOptical(mParent)? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); // getWidth() return value = mright-mleft = r-l = right boundary of the child View - left boundary of the child View = width... }Copy the code

2.3 summarize


3. Application scenarios

  • GetMeasuredWidth ()/getMeasuredHeight() is assigned during a Measure process, so values obtained after the Measure process are meaningful
  • Similarly, getWidth()/getHeight() is assigned during Layout, so the values obtained after Layout are meaningful

Therefore, the application scenarios of the two are as follows:

  • GetMeasuredWidth ()/getMeasuredHeight() : Gets the View width/height in onLayout()
  • GetWidth ()/getHeight() : Gets the View’s width/height in a place other than onLayout()

4. Pay extra attention

4.1 Inequality

  • Q: As mentioned above, in general, both get the same width/height. So what is the “unusual” case? (i.e., they are not equal)
  • A: Manual setting: forcing it by overwriting the View layout ()
@override public void layout(int l, int t, int r, int b){super.layout(l, t, r+100, b+100); }Copy the code
  • Effect: In any case, getWidth()/getHeight() will always be 100px wider/taller than getMeasuredWidth()/getMeasuredHeight()
  • The final width/height of the View is always 100px larger than the measured width/height

Although this artificial setting is not practical, it proves that the final width/height of the View can be different from the measured width/height

4.2 the rumor

There is a reason circulating on the Internet that describes the relationship between the values of the two:

  • Their values are equal when the screen is wrapable;
  • GetMeasuredWidth () = getWidth() + The size not shown outside the screen, i.e., getMeasuredWidth() is the actual size of the view, independent of the screen; The size of getHeight is the size of the screen

Below, I use an example to carry on refutation!

  • Example: Change the size of the button (no larger than the screen & no larger than the screen) and use getWidth() & getMeasureWidth() in onWindowFocusChanged () to get the width of the button, respectively, for verification
  • Note: Because the View has already been measured when onWindowFocusChanged (), that is, the process of Measure & Layout has been completed, we choose to obtain it in this method
  • The implementation code
public class MainActivity extends AppCompatActivity { private Button mBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBtn = (Button) findViewById(R.id.button); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); System.out.println("mBtn.getWidth() = " + mBtn.getWidth()); System.out.println( "mBtn.getMeasureWidth() = " + mBtn.getMeasuredWidth()); }}Copy the code

Case 1: Button size does not exceed the screen

<Button android:id="@+id/ Button "Android :layout_width="300px" Android :layout_height="300px" Android :text=" Carson: demo"/>Copy the code

Test result: The two are equal

Case 2: Button size is out of screen

<Button android:id="@+id/button" android:layout_width="2000px" android:layout_height="300px" Android: text = "demo of Carson" / >Copy the code

Test result: the two are still equal!

Final Conclusion: In non-human Settings, the width/height obtained by getWidth()/getHeight() is always the same as the width/height obtained by getMeasuredWidth()/getMeasuredHeight().


5. To summarize

  • Here’s a graph to summarize the differences between getMeasuredWidth()/getMeasuredHeight() and getWidth()/getHeight() :

  • Next, I will continue to explain the application of custom View. If you are interested, you can continue to follow the CSDN blog of Carson_ho, the technical blog I run

Please give the top/comment a thumbs up! Because your approval/encouragement is my biggest motivation to write!