安卓高手之路 图形系统(4 Measure的算法)

安卓高手之路 图形系统(4 Measure的算法) - 修补C++ - ITeye技术网站

Java代码  技术分享
  1.           
  2.   
  3.   
  4. /** 
  5.     * Does the hard part of measureChildren: figuring out the MeasureSpec to 
  6.     * pass to a particular child. This method figures out the right MeasureSpec 
  7.     * for one dimension (height or width) of one child view. 
  8.     * 
  9.     * The goal is to combine information from our MeasureSpec with the 
  10.     * LayoutParams of the child to get the best possible results. For example, 
  11.     * if the this view knows its size (because its MeasureSpec has a mode of 
  12.     * EXACTLY), and the child has indicated in its LayoutParams that it wants 
  13.     * to be the same size as the parent, the parent should ask the child to 
  14.     * layout given an exact size. 
  15.     * 
  16.     * @param spec The requirements for this view 
  17.     * @param padding The padding of this view for the current dimension and 
  18.     *        margins, if applicable 
  19.     * @param childDimension How big the child wants to be in the current 
  20.     *        dimension 
  21.     * @return a MeasureSpec integer for the child 
  22.     */  
  23.    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {  
  24.        int specMode = MeasureSpec.getMode(spec);  
  25.        int specSize = MeasureSpec.getSize(spec);  
  26.   
  27.        int size = Math.max(0, specSize - padding);  
  28.   
  29.        int resultSize = 0;  
  30.        int resultMode = 0;  
  31.   
  32.        switch (specMode) {  
  33.        // Parent has imposed an exact size on us  
  34.        case MeasureSpec.EXACTLY:  
  35.            if (childDimension >= 0) {  
  36.                resultSize = childDimension;  
  37.                resultMode = MeasureSpec.EXACTLY;  
  38.            } else if (childDimension == LayoutParams.MATCH_PARENT) {  
  39.                // Child wants to be our size. So be it.  
  40.                resultSize = size;  
  41.                resultMode = MeasureSpec.EXACTLY;  
  42.            } else if (childDimension == LayoutParams.WRAP_CONTENT) {  
  43.                // Child wants to determine its own size. It can‘t be  
  44.                // bigger than us.  
  45.                resultSize = size;  
  46.                resultMode = MeasureSpec.AT_MOST;  
  47.            }  
  48.            break;  
  49.   
  50.        // Parent has imposed a maximum size on us  
  51.        case MeasureSpec.AT_MOST:  
  52.            if (childDimension >= 0) {  
  53.                // Child wants a specific size... so be it  
  54.                resultSize = childDimension;  
  55.                resultMode = MeasureSpec.EXACTLY;  
  56.            } else if (childDimension == LayoutParams.MATCH_PARENT) {  
  57.                // Child wants to be our size, but our size is not fixed.  
  58.                // Constrain child to not be bigger than us.  
  59.                resultSize = size;  
  60.                resultMode = MeasureSpec.AT_MOST;  
  61.            } else if (childDimension == LayoutParams.WRAP_CONTENT) {  
  62.                // Child wants to determine its own size. It can‘t be  
  63.                // bigger than us.  
  64.                resultSize = size;  
  65.                resultMode = MeasureSpec.AT_MOST;  
  66.            }  
  67.            break;  
  68.   
  69.        // Parent asked to see how big we want to be  
  70.        case MeasureSpec.UNSPECIFIED:  
  71.            if (childDimension >= 0) {  
  72.                // Child wants a specific size... let him have it  
  73.                resultSize = childDimension;  
  74.                resultMode = MeasureSpec.EXACTLY;  
  75.            } else if (childDimension == LayoutParams.MATCH_PARENT) {  
  76.                // Child wants to be our size... find out how big it should  
  77.                // be  
  78.                resultSize = 0;  
  79.                resultMode = MeasureSpec.UNSPECIFIED;  
  80.            } else if (childDimension == LayoutParams.WRAP_CONTENT) {  
  81.                // Child wants to determine its own size.... find out how  
  82.                // big it should be  
  83.                resultSize = 0;  
  84.                resultMode = MeasureSpec.UNSPECIFIED;  
  85.            }  
  86.            break;  
  87.        }  
  88.        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);  
  89.    }  
 /**
     * Does the hard part of measureChildren: figuring out the MeasureSpec to
     * pass to a particular child. This method figures out the right MeasureSpec
     * for one dimension (height or width) of one child view.
     *
     * The goal is to combine information from our MeasureSpec with the
     * LayoutParams of the child to get the best possible results. For example,
     * if the this view knows its size (because its MeasureSpec has a mode of
     * EXACTLY), and the child has indicated in its LayoutParams that it wants
     * to be the same size as the parent, the parent should ask the child to
     * layout given an exact size.
     *
     * @param spec The requirements for this view
     * @param padding The padding of this view for the current dimension and
     *        margins, if applicable
     * @param childDimension How big the child wants to be in the current
     *        dimension
     * @return a MeasureSpec integer for the child
     */
    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
        case MeasureSpec.EXACTLY:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size. So be it.
                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.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent has imposed a maximum size on us
        case MeasureSpec.AT_MOST:
            if (childDimension >= 0) {
                // Child wants a specific size... so be it
                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.
                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.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent asked to see how big we want to be
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) {
                // Child wants a specific size... let him have it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size... find out how big it should
                // be
                resultSize = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size.... find out how
                // big it should be
                resultSize = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
        }
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }

 这个Measure算法主要是算child的测量方式和大小的。主要根据两种根据:

1. 自身的测量方式(MeasureSpec EXACTLY,AT_MOST,UNSPECIFIED)【这个是parent传过来的】
2. 自身的大小 【这个是parent传过来的】
3. 自己的padding【计算得到】
4. child的大小【child的LayoutParam得到】

根据以上四个推测出child的MeasureSpec 。也就是大小和测量方式。

child的请求大小来确定到底child应该有多宽以及应该怎么测量。

下面的逻辑比较多。

1.如果当前View是Exactly。那么也就是说有了固定的大小。
  
  那么Child如果说是一个固定的LayoutParam.width 或者 height,那么返回结果resultSize 就设置为这个固定值。
 
 
 
 

如果child是wrapContent,那么resultSize 就设置为当前这个View的工作区大小。也就是去除pad和margin
  的大小。同时,测量方式设置为AT_MOST

如果child是match_parent,那么由于当前View是固定大小的。那么resultSize 就设置为当前这个View的工作区大小。也就是去除pad和margin
  的大小。同时,测量方式设置为EXACTLY

2.如果当前View是MeasureSpec.AT_MOST。也就是说有个最大值。也是这三种情况
  a.fixed
     这个时候,当前View可以无限大,并且child有个固定值。那么就设置这个值吧。   这个地方
,没有做越界判断,因此有时候会出现一个子View非常大,撑破了父View的情况。google在这里
算不算是一个bug呢?也就是当前的currrentView为wrap_content.但是parentView却有一个fixed value。 同时,childView也有一个fixed Value。这个时候,如果childView的大小超过了parentView。 则会出现childView显示不全的现象。
  b.wrap_content
    
     同理,传入AT_MOST.但是不超过当前View的大小。【这个是与当前View为EXACTLY的情况一样】
    
  c.fill_parent

       这种情况也非常奇怪。发生在
currentView是wrap_content.而childView是fill_parent的情况。这个时候就没办法搞了。
这个时候,就告诉子View你也没有固定的大小。也就是说循环依赖产生了。唯一的办法是让childView 继续wrap_content.也就是废掉这个fill_parent。从而打破了这种循环依赖。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。