測(cè)量View(一):創(chuàng)建View并測(cè)量 http://www.reibang.com/p/4fb206b947ee
測(cè)量View(三):獲得測(cè)量寬高及真實(shí)寬高 http://www.reibang.com/p/cbd758a5b5cf
測(cè)量的寬高 與真實(shí)寬高 的區(qū)別
很簡(jiǎn)單用ScrollView舉例凌摄,當(dāng)ScrollView中有很多內(nèi)容一屏顯示不全時(shí)温艇,此時(shí)測(cè)量的高度(HorizontalScrollView寬度)是超過(guò)屏幕的高度(寬度)的肆捕,但是手機(jī)最終展示給用戶時(shí)的真實(shí)寬高所占的尺寸最多不超過(guò)屏幕的尺寸悬垃。
測(cè)量的寬高
在正確獲得View的寬高前,我們來(lái)分析一下原碼
view.getMeasuredWidth();
view.getMeasuredHeight();
View:getMeasuredWidth();
public final int getMeasuredWidth() {
return mMeasuredWidth & MEASURED_SIZE_MASK;
}
View:getMeasuredHeight();
public final int getMeasuredHeight() {
return mMeasuredHeight & MEASURED_SIZE_MASK;
}
以上返回的是該 View 的原始寬度和高度
查看View對(duì)mMeasuredWidth及mMeasuredHeight的引用發(fā)現(xiàn)setMeasuredDimensionRaw方法對(duì)其進(jìn)行賦值:
private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;
mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
}
回看調(diào)用順序
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;
}
setMeasuredDimensionRaw(measuredWidth, measuredHeight);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
以上這里看到了熟悉的方法onMeasure() ;
小結(jié):如果想得到measuredWidth 及measuredHeight 要調(diào)用 onMeasure() 即:measure()
真實(shí)的寬高
view.getWidth();
view.getHeight();
View:getWidth();
public final int getWidth() {
return mRight - mLeft;
}
View.getHeight();
public final int getHeight() {
return mBottom - mTop;
}
以上涉及到四個(gè)變量不難看出為View的坐標(biāo)
同樣的方法找到幾個(gè)相應(yīng)的方法
public final void setLeft(int left) {
...
mLeft = left;
...
}
public final void setRight(int right) {
...
mRight = right;
...
}
public final void setTop(int top) {
...
mTop = top;
...
}
public final void setBottom(int bottom) {
...
mBottom = bottom;
...
}
細(xì)心的朋友已經(jīng)發(fā)現(xiàn)以上方法為final的
而且查看注釋發(fā)現(xiàn):
This method is meant to be called by the layout system and should not generally be called otherwise, because the property may be changed at any time by the layout.
簡(jiǎn)單說(shuō)就是該方法應(yīng)由布局系統(tǒng)調(diào)用茬祷,不能隨便調(diào)用
繼續(xù)找發(fā)現(xiàn):
protected boolean setFrame(int left, int top, int right, int bottom) {
...
mLeft = left;
mTop = top;
mRight = right;
mBottom = bottom;
...
}
/**
* Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}.
* @hide
*/
//與setFrame相同, 但是@hide被隱藏
public void setLeftTopRightBottom(int left, int top, int right, int bottom) {
setFrame(left, top, right, bottom);
}
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);
...
}
//最終還是調(diào)用的setFrame()方法
private boolean setOpticalFrame(int left, int top, int right, int bottom) {
Insets parentInsets = mParent instanceof View ?
((View) mParent).getOpticalInsets() : Insets.NONE;
Insets childInsets = getOpticalInsets();
return setFrame(
left + parentInsets.left - childInsets.left,
top + parentInsets.top - childInsets.top,
right + parentInsets.left + childInsets.right,
bottom + parentInsets.top + childInsets.bottom);
}
以上又看到我們熟悉的方法
要獲得View的真實(shí)寬高,需要調(diào)用 layout()
總結(jié):
getWidth(): View在設(shè)定好布局后的寬墓塌。
getMeasuredWidth(): 對(duì)View測(cè)量后得到的測(cè)量寬度