在重写的onMeasure的时候我们会调用super.onMeasure(widthMeasureSpec, heightMeasureSpec);
来一起看下源码:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
原来就是默认的为我们调用了setMeasuredDimension(设置控件需要绘制的大小),英文是Measure测量其实就可以理解为计算并设置出该控件需要的大小。
继续来看setMeasuredDimension方法
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
boolean optical = isLayoutModeOptical(this);
if (optical != isLayoutModeOptical(mParent)) {
Insets insets = getOpticalInsets();
int opticalWidth = insets.left + insets.right;
int opticalHeight = insets.top + insets.bottom;
measuredWidth += optical ? opticalWidth : -opticalWidth;
measuredHeight += optical ? opticalHeight : -opticalHeight;
}
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;
mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
}
isLayoutModeOptical返回的boolean类型,返回的是是否超出了我们的视觉边界,
大家使用的时候都知道我们要传入的
widthMeasureSpec, heightMeasureSpec是父控件的宽和高,这里就解释了为什么我们需要传入这两个值了,就是为了控制不超出父控件的大小
。
现在来看看measureChild和measureChildren:
measureChild是用来测量子View的宽高(我更倾向于理解为设置子View的宽高)。
measureChild(View child, int parentWidthMeasureSpec,int parentHeightMeasureSpec);
见源码
protected void measureChild(View child, int parentWidthMeasureSpec,
int parentHeightMeasureSpec) {
final LayoutParams lp = child.getLayoutParams();
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight, lp.width);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop + mPaddingBottom, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
getChildMeasureSpec有三个参数,第一个是需要的大小(这里传的父控件的长宽,与上面的OnMeasure原理类似),第二个是当前子View的padding大小,第三个是此子View当前想要的设置的大小。
child.measure就是计算并设置出该child需要的大小。
所以每次我们在自定义View中得到测量(按英文就是测量...)子View的宽和高之后可以直接得到子View的宽高。
<span style="white-space:pre"> </span>View child = getChildAt(i);
// 测量子View的宽和高
measureChild(child, widthMeasureSpec, heightMeasureSpec);
// 得到LayoutParams
MarginLayoutParams lp = (MarginLayoutParams) child
.getLayoutParams();
// 子View占据的宽度
int childWidth = child.getMeasuredWidth() + lp.leftMargin
+ lp.rightMargin;
// 子View占据的高度
int childHeight = child.getMeasuredHeight() + lp.topMargin
+ lp.bottomMargin;
measureChildren是用来测量所有子View的宽高。
理解起来很简单:
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
final int size = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < size; ++i) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
}
就是遍历所有的children,当不是GONE时调用
measureChild方法...
最近开始看源码之后,发现以前好多看视频看书不知道的地方都可以直接理解了,大部分的教程都只会教你怎么调用而不告诉你原因,所以就学了忘,忘了再看,看了一遍又一遍,效率极低...
上面博客有什么错误的地方希望大家指正,有不理解的可以一起交流。