注意:1.以下measurespec用ms來代替(ms具體會在後面介紹)
2.該時序圖描述的是從viewrootimpl開始的measure()過程,因為viewrootimpl是window與view連線的樞紐
3.該時序圖著重於大概流程及重要方法的作用,具體**細節會放到後面介紹
4.decorview作為頂級view,本身是乙個framelayout,所以也是乙個viewgroup
在view的測量過程中,ms起著非常重要的作用,ms在某種程度上來說更像是一種測量的標準。
ms是乙個32位的int值,前2位代表測量模式,後30位代表測量大小
測量模式(specmode)一共分為3種:
unspecified: 父容器不對子view限制,這種情況一般我們用不到,系統內部使用
exactly : 父容器可以算出view的具體的大小,一般對應於 具體值或者match_parent
at_most : 父容器指定乙個值,子view不能超過這個值,一般對應於 wrap_content
一般情況下,乙個view的ms的測量是根據父容器的ms和本身的layoutparams來決定的,根據一些規則,在父容器中算出ms,然後父容器呼叫此view的measure()方法將結果傳給該view,該view接著會回掉onmeasure()將結果傳給該view的實現類。 但是decorview作為頂級view是沒有父容器的,所以decorview的ms是根據視窗的大小和自身的layoutparams來決定的。
--
/*** desirewindowwidth : 代表螢幕的寬頻 ,同理,dwh 代表螢幕的高度
**/private boolean measurehierarchy(final view host, final windowmanager.layoutparams lp,
final resources res, final int desiredwindowwidth, final int desiredwindowheight)
/*** 計算出decorview的ms*
**/private static int getrootmeasurespec(int windowsize, int rootdimension)
return measurespec;
protected void measurechildwithmargins(view child,
int parentwidthmeasurespec, int widthused,
int parentheightmeasurespec, int heightused)
//根據父容器的ms和自身的layoutparams求出該view的ms的具體操作
public static int getchildmeasurespec(int spec, int padding, int childdimension) else if (childdimension == layoutparams.match_parent) else if (childdimension == layoutparams.wrap_content)
break;
// parent has imposed a maximum size on us
case measurespec.at_most:
if (childdimension >= 0) else if (childdimension == layoutparams.match_parent) else if (childdimension == layoutparams.wrap_content)
break;
// parent asked to see how big we want to be
case measurespec.unspecified:
if (childdimension >= 0) else if (childdimension == layoutparams.match_parent) else if (childdimension == layoutparams.wrap_content)
break;
}return measurespec.makemeasurespec(resultsize, resultmode);
}
一般view的measure()方法如下:
public final void measure(int widthmeasurespec, int heightmeasurespec) else
// flag not set, setmeasureddimension() was not invoked, we raise
// an exception to warn the developer
if ((mprivateflags & pflag_measured_dimension_set) != pflag_measured_dimension_set)
mprivateflags |= pflag_layout_required;
}
// 將ms值儲存起來,為了提高效能,如果下次進來並且標誌沒變,就不會再重複執行onmeasure()
moldwidthmeasurespec = widthmeasurespec;
moldheightmeasurespec = heightmeasurespec;
mmeasurecache.put(key, ((long) mmeasuredwidth) << 32 |
(long) mmeasuredheight & 0xffffffffl); // suppress sign extension
}viewgroup 的 measure();
view是乙個容器,他不但要完成自己的測量方法,還需要遍歷onmeasure()計算出下一層級的ms,下面以framelayout的onmeasure方法為講解
@override
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) }}
}// account for padding too
maxwidth += getpaddingleftwithforeground() + getpaddingrightwithforeground();
maxheight += getpaddingtopwithforeground() + getpaddingbottomwithforeground();
// check against our minimum height and width
maxheight = math.max(maxheight, getsuggestedminimumheight());
maxwidth = math.max(maxwidth, getsuggestedminimumwidth());
// check against our foreground's minimum height and width
final drawable drawable = getforeground();
if (drawable != null)
setmeasureddimension(resolvesizeandstate(maxwidth, widthmeasurespec, childstate),
resolvesizeandstate(maxheight, heightmeasurespec,
childstate << measured_height_state_shift));
count = mmatchparentchildren.size();
if (count > 1) else
if (lp.height == layoutparams.match_parent) else
//呼叫子類的measure()方法進行傳遞
child.measure(childwidthmeasurespec, childheightmeasurespec);}}
}
View工作原理 Measure過程
知識點 view的measure過程和activity的生命週期不同步 一 view的measure過程 measure是final,不可重寫 measure onmeasure setmeasureddimension getdefaultsize這裡atmost和exactly進行了相同的操作 ...
普通View的measure流程
對於普通的view,其測量在viewgroup中的measurechildwithmargins函式中呼叫child view的measure開始測量。1 從measure函式開始 1 public final void measure int widthmeasurespec,int height...
View框架之layout 流程
注意 rootview是乙個framelayout,所以也是乙個viewgroup 這裡的的host就是我們的根布局decorview,因為decorview是乙個framelayout,而layout 是view中被修飾final的方法,所以我們這裡呼叫的是view的layout的方法,layou...