Android View measure (二) 自定义UI控件measure相关
本篇模拟三个角色:Android 架构师-小福、Android 控件开发工程师-小黑、 Android 开发工程师-小白,下面按照三个角色不同角度分析measure过程。
小福负责分享:
- measure的本质
- measure代码流程
- onMeasure方法与MeasureSpec
- 提出问题
小黑负责分享:
- 布局控件开发中覆写Measure例子 - ok
- 从遇到的一个异常说起
- 什么时候需要覆写onMeaure? - ok
- view.getWidth与view.getMeasureWidth区别 - ok
Android 控件开发工程师-小黑的分享
一、布局控件开发中覆写Measure例子
二、从遇到的一个异常说起
java.lang.IllegalStateException: onMeasure() did not set the measured dimension by calling setMeasuredDimension()
三、什么时候需要覆写onMeaure?
四、view.getWidth()与view.getMeasuredWidth()区别
public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Callback, AccessibilityEventSource { /** * Like {@link #getMeasuredWidthAndState()}, but only returns the * raw width component (that is the result is masked by * {@link #MEASURED_SIZE_MASK}). * * @return The raw measured width of this view. */ public final int getMeasuredWidth() { // 直接返回mMeasuredWidth与后者相与清理掉其他开关获取真是measure大小 return mMeasuredWidth & MEASURED_SIZE_MASK; } /** * <p>This mehod must be called by {@link #onMeasure(int, int)} to store the * measured width and measured height. Failing to do so will trigger an * exception at measurement time.</p> * * @param measuredWidth The measured width of this view. May be a complex * bit mask as defined by {@link #MEASURED_SIZE_MASK} and * {@link #MEASURED_STATE_TOO_SMALL}. * @param measuredHeight The measured height of this view. May be a complex * bit mask as defined by {@link #MEASURED_SIZE_MASK} and * {@link #MEASURED_STATE_TOO_SMALL}. */ protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { // 通常在onMeasure中调用,传入测量过的视图宽度与高度 mMeasuredWidth = measuredWidth; mMeasuredHeight = measuredHeight; mPrivateFlags |= MEASURED_DIMENSION_SET; } /** * Bits of {@link #getMeasuredWidthAndState()} and * {@link #getMeasuredWidthAndState()} that provide the actual measured size. */ // MeasureSpec中的Mode或占用int类型中前几位 public static final int MEASURED_SIZE_MASK = 0x00ffffff; }
从上面两个方法可以看出getMeasuredWidth的值是从mMeasuredWidth变量获取,而这个变量仅在View.setMeasuredDimension方法中继续初始化,从setMeasuredDimension方法的注释中就可以看出这个方式是在onMeasure中被调用,也就是getMeasuredWidth获取到的是在视图onMeasure方法中已经获取到视图的大小之后,才能进行赋值。getMeasuredWidth获取的是通过onMeasure测量后的值,在onMeasure执行之前可以调用但是获取到的都是0(int类型的默认初始化值)。
public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Callback, AccessibilityEventSource { /** * Return the width of the your view. * * @return The width of your view, in pixels. */ @ViewDebug.ExportedProperty(category = "layout") public final int getWidth() { // 视图的右侧减去左侧的值 return mRight - mLeft; } /** * Assign a size and position to this view. * * This is called from layout. * * @param left Left position, relative to parent * @param top Top position, relative to parent * @param right Right position, relative to parent * @param bottom Bottom position, relative to parent * @return true if the new size and position are different than the * previous ones * {@hide} */ protected boolean setFrame(int left, int top, int right, int bottom) { boolean changed = false; ...... // 四个值中任意一个发生改变就行 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { changed = true; ...... mLeft = left; mTop = top; mRight = right; mBottom = bottom; ...... } return changed; } public void layout(int l, int t, int r, int b) { ...... // 当前视图布局时执行,传入当前视图的上下左右边界值 boolean changed = setFrame(l, t, r, b); if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) { ...... // 上面执行完成后才会触发onLayout onLayout(changed, l, t, r, b); ...... } ...... mPrivateFlags &= ~FORCE_LAYOUT; } }
从上面的代码可以看出当视图layout操作时,会先调用setFrame方法传入left, top, right, bottom 这些值会在以后layout布局分析是进行详细解释,这些值是其父视图给他当前视图设定的可显示位置与大小(right - left 与 top - bottom获得)。 getWidth方法获取的宽度是当前视图可以在屏幕实际上占据的大小。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。