總結來說 mode 取值 受父容器與子控件共同決定
在自定義控件時為了滿足特定需求,widget大都是我們自己測量的。
大家都知道測量時最重要的步驟就是重寫onMeasure方法,來計算出寬高。
這裏面的MeasureSpec 很重要,大家也都知道,它是一個java中的靜態類,它有重要的三個靜態常量和三個最重要的靜態方法。
我這裏說下MeasureSpec 的3中模式
UNSPECIFIED(未指定),父元素部隊自元素施加任何束縛,子元素可以得到任意想要的大小;
EXACTLY(完全),父元素決定自元素的確切大小,子元素將被限定在給定的邊界裏而忽略它本身大小;
AT_MOST(至多),子元素至多達到指定大小的值。
看過很多博客,大家總結說,模式和XML布局有如下對應關系:
wrap_content-> MeasureSpec.AT_MOST
match_parent -> MeasureSpec.EXACTLY
50dp(確切值) -> MeasureSpec.EXACTLY
但是在具體開發中 我發現並不是一定這樣,然後就看了下源碼,才發現子控件的mode不只是與自身的設置有關系,它還受到父容器影響。
getChildMeasureSpec() 方法
[java] view plain copy
- public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
- int specMode = MeasureSpec.getMode(spec);
- int specSize = MeasureSpec.getSize(spec);
- int size = Math.max(0, specSize - padding);
- int resultSize = 0;
- int resultMode = 0;
- switch (specMode) {
- // Parent has imposed an exact size on us
- // 父容器是 EXACTLY 模式
- case MeasureSpec.EXACTLY:
- if (childDimension >= 0) {
- // 如果 child 希望有自己的尺寸,那麽允許它,並把它的測量模式設置為 EXACTLY
- resultSize = childDimension;
- resultMode = MeasureSpec.EXACTLY;
- } else if (childDimension == LayoutParams.MATCH_PARENT) {
- // Child wants to be our size. So be it.
- // child 希望尺寸與 父容器 一樣大,那麽允許它
- resultSize = size;
- resultMode = MeasureSpec.EXACTLY;
- } else if (childDimension == LayoutParams.WRAP_CONTENT) {
- // Child wants to determine its own size. It can‘t be
- // bigger than us.
- // child 希望由自己決定自己的尺寸,但是有個前提是它不能大於 父容器 本身給的建議值。
- // 並且需要設置它的測量模式為 AT_MOST
- resultSize = size;
- resultMode = MeasureSpec.AT_MOST;
- }
- break;
- // Parent has imposed a maximum size on us
- // 父容器是 AT_MOST 模式,對於 父容器 本身而言,它也有個最大的尺寸約束
- case MeasureSpec.AT_MOST:
- if (childDimension >= 0) {
- // Child wants a specific size... so be it
- // 如果 child 希望有自己的尺寸,那麽允許它,並把它的測量模式設置為 EXACTLY
- resultSize = childDimension;
- resultMode = MeasureSpec.EXACTLY;
- } else if (childDimension == LayoutParams.MATCH_PARENT) {
- // Child wants to be our size, but our size is not fixed.
- // Constrain child to not be bigger than us.
- // child 希望尺寸和 父容器 一樣大,那麽允許它,但是 父容器 本身有限制,所以也
- // 需要給 child 加一個限制,這個限制就是將 child 模式設置為 AT_MOST
- resultSize = size;
- resultMode = MeasureSpec.AT_MOST;
- } else if (childDimension == LayoutParams.WRAP_CONTENT) {
- // Child wants to determine its own size. It can‘t be
- // bigger than us.
- // child 希望由自己決定自己的尺寸,但是有個前提是它不能大於 父容器 本身給的建議值。
- // 並且需要設置它的測量模式為 AT_MOST
- resultSize = size;
- resultMode = MeasureSpec.AT_MOST;
- }
- break;
- // Parent asked to see how big we want to be
- // 父容器是 UNSPECIFIED 模式,對於 父容器 本身而言,它的期望值是想要多大就多大,讓 父容器 的 parent不要限制它。
- case MeasureSpec.UNSPECIFIED:
- if (childDimension >= 0) {
- // Child wants a specific size... let him have it
- //如果 child 希望有自己的尺寸,那麽允許它,並把它的測量模式設置為 EXACTLY
- resultSize = childDimension;
- resultMode = MeasureSpec.EXACTLY;
- } else if (childDimension == LayoutParams.MATCH_PARENT) {
- // Child wants to be our size... find out how big it should
- // be
- // child 希望尺寸和 父容器 一樣大,那麽允許它,但是 父容器 本身也需要計算,所以只能設置為0,並且
- // 將child的測量模式設置為 UNSPECIFIED
- resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
- resultMode = MeasureSpec.UNSPECIFIED;
- } else if (childDimension == LayoutParams.WRAP_CONTENT) {
- // Child wants to determine its own size.... find out how
- // big it should be
- // child 希望尺寸由自己決定,一般這個時候,父容器 會給它一個 Size 作為最大值限制,
- // 但是 父容器 本身也需要計算,所以只能設置為0,並且沒有給child最大值的設定
- // 將child的測量模式設置為 UNSPECIFIED
- resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
- resultMode = MeasureSpec.UNSPECIFIED;
- }
- break;
- }
- //noinspection ResourceType
- return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
- }
總結來說 mode 取值 受父容器與子控件共同決定
父容器是MeasureSpec.EXACTLY模式
子控件是具體值, mode = MeasureSpec.EXACTLY
子控件是MATCH_PARENT, mode = MeasureSpec.EXACTLY
子控件是WRAP_CONTENT, mode = MeasureSpec.AT_MOST
父容器是MeasureSpec.AT_MOST模式
子控件是具體值, mode = MeasureSpec.EXACTLY
子控件是MATCH_PARENT, mode = MeasureSpec.AT_MOST
子控件是WRAP_CONTENT, mode = MeasureSpec.AT_MOST
父容器是MeasureSpec.UNSPECIFIED模式
子控件是具體值, mode = MeasureSpec.EXACTLY
子控件是MATCH_PARENT, mode = MeasureSpec.UNSPECIFIED
子控件是WRAP_CONTENT, mode = MeasureSpec.UNSPECIFIED
就這樣
總結來說 mode 取值 受父容器與子控件共同決定