Android开发中,对于自定义View,分为两种,一种 是自定义控件(继承View类),另一种是自定义布局容器(继承ViewGroup)。如果是自定义控件,则一般需要重载两个方法,一个是 onMeasure(),用来测量控件尺寸,另一个是onDraw(),用来绘制控件的UI。而自定义布局容器,则一般需要实现/重载三个方法,一个是 onMeasure(),也是用来测量尺寸;一个是onLayout(),用来布局子控件;还有一个是dispatchDraw(),用来绘制UI。

 

本文主要分析自定义ViewGroup的onLayout()方法的实现。

 

ViewGroup 类的onLayout()函数是abstract型,继承者必须实现,由于ViewGroup的定位就是一个容器,用来盛放子控件的,所以就必须定义要以 什么的方式来盛放,比如LinearLayout就是以横向或者纵向顺序存放,而RelativeLayout则以相对位置来摆放子控件,同样,我们的自 定义ViewGroup也必须给出我们期望的布局方式,而这个定义就通过onLayout()函数来实现。

 

我们通过实现一个水平优先布局的视图容器来更加深入地了解onLayout()的实现吧,效果如图所示(黑色方块为子控件,白色部分为自定义布局容器)。该容器的布局方式是,首先水平方向上摆放子控件,水平方向放不下了,则另起一行继续水平摆放。

 

wKiom1PzLDGz5ifsAABxoQ3CRhg847.jpg

 

**    1.  自定义ViewGroup的派生类**

 

第一步,则是自定ViewGroup的派生类,继承默认的构造函数。

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
      
      <div class="line number4 index3 alt1">
        4
      </div>
      
      <div class="line number5 index4 alt2">
        5
      </div>
      
      <div class="line number6 index5 alt1">
        6
      </div>
      
      <div class="line number7 index6 alt2">
        7
      </div>
      
      <div class="line number8 index7 alt1">
        8
      </div>
      
      <div class="line number9 index8 alt2">
        9
      </div>
      
      <div class="line number10 index9 alt1">
        10
      </div>
      
      <div class="line number11 index10 alt2">
        11
      </div>
      
      <div class="line number12 index11 alt1">
        12
      </div>
      
      <div class="line number13 index12 alt2">
        13
      </div>
      
      <div class="line number14 index13 alt1">
        14
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `public` `class` `CustomViewGroup ``extends` `ViewGroup {`
        </div>
        
        <div class="line number2 index1 alt1">
          ` `
        </div>
        
        <div class="line number3 index2 alt2">
          `   ``public` `CustomViewGroup(Context context) {`
        </div>
        
        <div class="line number4 index3 alt1">
          `       ``super``(context);    `
        </div>
        
        <div class="line number5 index4 alt2">
          `    ``}`
        </div>
        
        <div class="line number6 index5 alt1">
          ` `
        </div>
        
        <div class="line number7 index6 alt2">
          `   ``public` `CustomViewGroup(Context context, AttributeSet attrs) {`
        </div>
        
        <div class="line number8 index7 alt1">
          `       ``super``(context, attrs);     `
        </div>
        
        <div class="line number9 index8 alt2">
          `    ``}`
        </div>
        
        <div class="line number10 index9 alt1">
          `   `
        </div>
        
        <div class="line number11 index10 alt2">
          `   ``public` `CustomViewGroup(Context context, AttributeSet attrs, intdefStyle) {`
        </div>
        
        <div class="line number12 index11 alt1">
          `       ``super``(context, attrs, defStyle);`
        </div>
        
        <div class="line number13 index12 alt2">
          `    ``}`
        </div>
        
        <div class="line number14 index13 alt1">
          `}`
        </div>
      </div>
    </td>
  </tr>
</table>

 

**    2.  重载onMeasure()方法**

 

为什么要重载onMeasure()方法这里就不赘述了,上一篇文章已经讲过,这里需要注意的是,自定义ViewGroup的onMeasure()方法中,除了计算自身的尺寸外,还需要调用measureChildren()函数来计算子控件的尺寸

 

onMeasure()的定义不是本文的讨论重点,因此这里我直接使用默认的onMeasure()定义,当然measureChildren()是必须得加的。

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
      
      <div class="line number4 index3 alt1">
        4
      </div>
      
      <div class="line number5 index4 alt2">
        5
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `@Override`
        </div>
        
        <div class="line number2 index1 alt1">
          `protected` `void` `onMeasure(``int` `widthMeasureSpec, ``int` `heightMeasureSpec) {`
        </div>
        
        <div class="line number3 index2 alt2">
          `    ``measureChildren(widthMeasureSpec, heightMeasureSpec);`
        </div>
        
        <div class="line number4 index3 alt1">
          `    ``super``.onMeasure(widthMeasureSpec, heightMeasureSpec);  `
        </div>
        
        <div class="line number5 index4 alt2">
          `}`
        </div>
      </div>
    </td>
  </tr>
</table>

 

**    3.  实现onLayout()方法**

 

onLayout()函数的原型如下:

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `//@param changed 该参数指出当前ViewGroup的尺寸或者位置是否发生了改变`
        </div>
        
        <div class="line number2 index1 alt1">
          `//@param left top right bottom 当前ViewGroup相对于其父控件的坐标位置`
        </div>
        
        <div class="line number3 index2 alt2">
          `protected` `void` `onLayout(``boolean` `changed,``int` `left, ``int` `top, ``int` `right, ``int` `bottom);`
        </div>
      </div>
    </td>
  </tr>
</table>

 

由于我们希望优先横向布局子控件,那么,首先,我们知道总宽度是多少,这个值可以通过getMeasuredWidth()来得到,当然子控件的宽度也可以通过子控件对象的getMeasuredWidth()来得到。

 

这样,就不复杂了,具体的实现代码如下所示:

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
      
      <div class="line number4 index3 alt1">
        4
      </div>
      
      <div class="line number5 index4 alt2">
        5
      </div>
      
      <div class="line number6 index5 alt1">
        6
      </div>
      
      <div class="line number7 index6 alt2">
        7
      </div>
      
      <div class="line number8 index7 alt1">
        8
      </div>
      
      <div class="line number9 index8 alt2">
        9
      </div>
      
      <div class="line number10 index9 alt1">
        10
      </div>
      
      <div class="line number11 index10 alt2">
        11
      </div>
      
      <div class="line number12 index11 alt1">
        12
      </div>
      
      <div class="line number13 index12 alt2">
        13
      </div>
      
      <div class="line number14 index13 alt1">
        14
      </div>
      
      <div class="line number15 index14 alt2">
        15
      </div>
      
      <div class="line number16 index15 alt1">
        16
      </div>
      
      <div class="line number17 index16 alt2">
        17
      </div>
      
      <div class="line number18 index17 alt1">
        18
      </div>
      
      <div class="line number19 index18 alt2">
        19
      </div>
      
      <div class="line number20 index19 alt1">
        20
      </div>
      
      <div class="line number21 index20 alt2">
        21
      </div>
      
      <div class="line number22 index21 alt1">
        22
      </div>
      
      <div class="line number23 index22 alt2">
        23
      </div>
      
      <div class="line number24 index23 alt1">
        24
      </div>
      
      <div class="line number25 index24 alt2">
        25
      </div>
      
      <div class="line number26 index25 alt1">
        26
      </div>
      
      <div class="line number27 index26 alt2">
        27
      </div>
      
      <div class="line number28 index27 alt1">
        28
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `protected` `void` `onLayout(``boolean` `changed, ``int` `left, ``int` `top, ``int` `right, ``int` `bottom) {`
        </div>
        
        <div class="line number2 index1 alt1">
          `    `
        </div>
        
        <div class="line number3 index2 alt2">
          `    ``int` `mViewGroupWidth  = getMeasuredWidth();  ``//当前ViewGroup的总宽度       `
        </div>
        
        <div class="line number4 index3 alt1">
        </div>
        
        <div class="line number5 index4 alt2">
          `    ``int` `mPainterPosX = left;  ``//当前绘图光标横坐标位置`
        </div>
        
        <div class="line number6 index5 alt1">
          `    ``int` `mPainterPosY = top;  ``//当前绘图光标纵坐标位置  `
        </div>
        
        <div class="line number7 index6 alt2">
          `    `
        </div>
        
        <div class="line number8 index7 alt1">
          `    ``int` `childCount = getChildCount();        `
        </div>
        
        <div class="line number9 index8 alt2">
          `    ``for` `( ``int` `i = ````; i &lt; childCount; i++ ) {`
        </div>
        
        <div class="line number10 index9 alt1">
          `        `
        </div>
        
        <div class="line number11 index10 alt2">
          `        ``View childView = getChildAt(i);`
        </div>
        
        <div class="line number12 index11 alt1">
        </div>
        
        <div class="line number13 index12 alt2">
          `        ``int` `width  = childView.getMeasuredWidth();`
        </div>
        
        <div class="line number14 index13 alt1">
          `        ``int` `height = childView.getMeasuredHeight();             `
        </div>
        
        <div class="line number15 index14 alt2">
          `                    `
        </div>
        
        <div class="line number16 index15 alt1">
          `        ``//如果剩余的空间不够,则移到下一行开始位置`
        </div>
        
        <div class="line number17 index16 alt2">
          `        ``if``( mPainterPosX + width &gt; mViewGroupWidth ) {              `
        </div>
        
        <div class="line number18 index17 alt1">
          `            ``mPainterPosX = left; `
        </div>
        
        <div class="line number19 index18 alt2">
          `            ``mPainterPosY += height;`
        </div>
        
        <div class="line number20 index19 alt1">
          `        ``}                    `
        </div>
        
        <div class="line number21 index20 alt2">
          `        `
        </div>
        
        <div class="line number22 index21 alt1">
          `        ``//执行ChildView的绘制`
        </div>
        
        <div class="line number23 index22 alt2">
          `        ``childView.layout(mPainterPosX,mPainterPosY,mPainterPosX+width, mPainterPosY+height);`
        </div>
        
        <div class="line number24 index23 alt1">
          `        `
        </div>
        
        <div class="line number25 index24 alt2">
          `        ``//记录当前已经绘制到的横坐标位置 `
        </div>
        
        <div class="line number26 index25 alt1">
          `        ``mPainterPosX += width;`
        </div>
        
        <div class="line number27 index26 alt2">
          `    ``}       `
        </div>
        
        <div class="line number28 index27 alt1">
          `}`
        </div>
      </div>
    </td>
  </tr>
</table>

 

**    4. 布局文件测试**

 

下面我们就尝试写一个简单的xml文件,来测试一下我们的自定义ViewGroup,我们把子View的背景颜色都设置为黑色,方便我们辨识。

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
      
      <div class="line number4 index3 alt1">
        4
      </div>
      
      <div class="line number5 index4 alt2">
        5
      </div>
      
      <div class="line number6 index5 alt1">
        6
      </div>
      
      <div class="line number7 index6 alt2">
        7
      </div>
      
      <div class="line number8 index7 alt1">
        8
      </div>
      
      <div class="line number9 index8 alt2">
        9
      </div>
      
      <div class="line number10 index9 alt1">
        10
      </div>
      
      <div class="line number11 index10 alt2">
        11
      </div>
      
      <div class="line number12 index11 alt1">
        12
      </div>
      
      <div class="line number13 index12 alt2">
        13
      </div>
      
      <div class="line number14 index13 alt1">
        14
      </div>
      
      <div class="line number15 index14 alt2">
        15
      </div>
      
      <div class="line number16 index15 alt1">
        16
      </div>
      
      <div class="line number17 index16 alt2">
        17
      </div>
      
      <div class="line number18 index17 alt1">
        18
      </div>
      
      <div class="line number19 index18 alt2">
        19
      </div>
      
      <div class="line number20 index19 alt1">
        20
      </div>
      
      <div class="line number21 index20 alt2">
        21
      </div>
      
      <div class="line number22 index21 alt1">
        22
      </div>
      
      <div class="line number23 index22 alt2">
        23
      </div>
      
      <div class="line number24 index23 alt1">
        24
      </div>
      
      <div class="line number25 index24 alt2">
        25
      </div>
      
      <div class="line number26 index25 alt1">
        26
      </div>
      
      <div class="line number27 index26 alt2">
        27
      </div>
      
      <div class="line number28 index27 alt1">
        28
      </div>
      
      <div class="line number29 index28 alt2">
        29
      </div>
      
      <div class="line number30 index29 alt1">
        30
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `&lt;com.titcktick.customview.CustomViewGroup xmlns:android=``"http://schemas.android.com/apk/res/android"`
        </div>
        
        <div class="line number2 index1 alt1">
          `    ``xmlns:tools=``"http://schemas.android.com/tools"`
        </div>
        
        <div class="line number3 index2 alt2">
          `    ``android:layout_width=``"match_parent"`
        </div>
        
        <div class="line number4 index3 alt1">
          `    ``android:layout_height=``"match_parent"``&gt;`
        </div>
        
        <div class="line number5 index4 alt2">
        </div>
        
        <div class="line number6 index5 alt1">
          `    ``&lt;View`
        </div>
        
        <div class="line number7 index6 alt2">
          `        ``android:layout_width=``"100dp"`
        </div>
        
        <div class="line number8 index7 alt1">
          `        ``android:layout_height=``"100dp"`
        </div>
        
        <div class="line number9 index8 alt2">
          `        ``android:layout_margin=``"10dp"`
        </div>
        
        <div class="line number10 index9 alt1">
          `        ``android:background=``"@android:color/black"``/&gt;`
        </div>
        
        <div class="line number11 index10 alt2">
          `    `
        </div>
        
        <div class="line number12 index11 alt1">
          `    ``&lt;View`
        </div>
        
        <div class="line number13 index12 alt2">
          `        ``android:layout_width=``"100dp"`
        </div>
        
        <div class="line number14 index13 alt1">
          `        ``android:layout_height=``"100dp"`
        </div>
        
        <div class="line number15 index14 alt2">
          `        ``android:layout_margin=``"10dp"`
        </div>
        
        <div class="line number16 index15 alt1">
          `        ``android:background=``"@android:color/black"``/&gt;     `
        </div>
        
        <div class="line number17 index16 alt2">
          `        `
        </div>
        
        <div class="line number18 index17 alt1">
          `    ``&lt;View`
        </div>
        
        <div class="line number19 index18 alt2">
          `        ``android:layout_width=``"100dp"`
        </div>
        
        <div class="line number20 index19 alt1">
          `        ``android:layout_height=``"100dp"`
        </div>
        
        <div class="line number21 index20 alt2">
          `        ``android:layout_margin=``"10dp"`
        </div>
        
        <div class="line number22 index21 alt1">
          `        ``android:background=``"@android:color/black"``/&gt;`
        </div>
        
        <div class="line number23 index22 alt2">
          `    `
        </div>
        
        <div class="line number24 index23 alt1">
          `    ``&lt;View`
        </div>
        
        <div class="line number25 index24 alt2">
          `        ``android:layout_width=``"100dp"`
        </div>
        
        <div class="line number26 index25 alt1">
          `        ``android:layout_height=``"100dp"`
        </div>
        
        <div class="line number27 index26 alt2">
          `        ``android:layout_margin=``"10dp"`
        </div>
        
        <div class="line number28 index27 alt1">
          `        ``android:background=``"@android:color/black"``/&gt;     `
        </div>
        
        <div class="line number29 index28 alt2">
        </div>
        
        <div class="line number30 index29 alt1">
          `&lt;/com.titcktick.customview.CustomViewGroup&gt;`
        </div>
      </div>
    </td>
  </tr>
</table>

 

**    5. 添加layout_margin**

 

为了让核心逻辑更加清晰,上面的onLayout()实现我隐去了margin的计算,这样就会导致子控件的layout_margin不起效果,所以上述效果是子控件一个个紧挨着排列,中间没有空隙。那么,下面我们来研究下如何添加margin效果。

 

其实,如 果要自定义ViewGroup支持子控件的layout_margin参数,则自定义的ViewGroup类必须重载 generateLayoutParams()函数,并且在该函数中返回一个ViewGroup.MarginLayoutParams派生类对象,这样 才能使用margin参数

 

ViewGroup.MarginLayoutParams的定义关键部分如下,它记录了子控件的layout_margin值:

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
      
      <div class="line number4 index3 alt1">
        4
      </div>
      
      <div class="line number5 index4 alt2">
        5
      </div>
      
      <div class="line number6 index5 alt1">
        6
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `public` `static` `class` `MarginLayoutParams ``extends` `ViewGroup.LayoutParams {        `
        </div>
        
        <div class="line number2 index1 alt1">
          `    ``public` `int` `leftMargin;`
        </div>
        
        <div class="line number3 index2 alt2">
          `    ``public` `int` `topMargin;`
        </div>
        
        <div class="line number4 index3 alt1">
          `    ``public` `int` `rightMargin;`
        </div>
        
        <div class="line number5 index4 alt2">
          `    ``public` `int` `bottomMargin;`
        </div>
        
        <div class="line number6 index5 alt1">
          `}`
        </div>
      </div>
    </td>
  </tr>
</table>

 

你可以跟踪源码看看,其实XML文件中View的layout_xxx参数都是被传递到了各种自定义ViewGroup.LayoutParams派生类对象中。例如LinearLayout的LayoutParams定义的关键部分如下:

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
      
      <div class="line number4 index3 alt1">
        4
      </div>
      
      <div class="line number5 index4 alt2">
        5
      </div>
      
      <div class="line number6 index5 alt1">
        6
      </div>
      
      <div class="line number7 index6 alt2">
        7
      </div>
      
      <div class="line number8 index7 alt1">
        8
      </div>
      
      <div class="line number9 index8 alt2">
        9
      </div>
      
      <div class="line number10 index9 alt1">
        10
      </div>
      
      <div class="line number11 index10 alt2">
        11
      </div>
      
      <div class="line number12 index11 alt1">
        12
      </div>
      
      <div class="line number13 index12 alt2">
        13
      </div>
      
      <div class="line number14 index13 alt1">
        14
      </div>
      
      <div class="line number15 index14 alt2">
        15
      </div>
      
      <div class="line number16 index15 alt1">
        16
      </div>
      
      <div class="line number17 index16 alt2">
        17
      </div>
      
      <div class="line number18 index17 alt1">
        18
      </div>
      
      <div class="line number19 index18 alt2">
        19
      </div>
      
      <div class="line number20 index19 alt1">
        20
      </div>
      
      <div class="line number21 index20 alt2">
        21
      </div>
      
      <div class="line number22 index21 alt1">
        22
      </div>
      
      <div class="line number23 index22 alt2">
        23
      </div>
      
      <div class="line number24 index23 alt1">
        24
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `public` `class` `LinearLayout ``extends` `ViewGroup {`
        </div>
        
        <div class="line number2 index1 alt1">
        </div>
        
        <div class="line number3 index2 alt2">
          `public` `static` `class` `LayoutParams ``extends` `ViewGroup.MarginLayoutParams {`
        </div>
        
        <div class="line number4 index3 alt1">
        </div>
        
        <div class="line number5 index4 alt2">
          `    ``public` `float` `weight;`
        </div>
        
        <div class="line number6 index5 alt1">
          `    ``public` `int` `gravity = -``1``;`
        </div>
        
        <div class="line number7 index6 alt2">
        </div>
        
        <div class="line number8 index7 alt1">
          `    ``public` `LayoutParams(Context c, AttributeSet attrs) {`
        </div>
        
        <div class="line number9 index8 alt2">
        </div>
        
        <div class="line number10 index9 alt1">
          `            ``super``(c, attrs);`
        </div>
        
        <div class="line number11 index10 alt2">
        </div>
        
        <div class="line number12 index11 alt1">
          `            ``TypedArray a = c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);`
        </div>
        
        <div class="line number13 index12 alt2">
          `            ``weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, ````);`
        </div>
        
        <div class="line number14 index13 alt1">
          `            ``gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -``1``);`
        </div>
        
        <div class="line number15 index14 alt2">
        </div>
        
        <div class="line number16 index15 alt1">
          `            ``a.recycle();`
        </div>
        
        <div class="line number17 index16 alt2">
          `        ``}`
        </div>
        
        <div class="line number18 index17 alt1">
          `    ``}`
        </div>
        
        <div class="line number19 index18 alt2">
        </div>
        
        <div class="line number20 index19 alt1">
          `    ``@Override`
        </div>
        
        <div class="line number21 index20 alt2">
          `    ``public` `LayoutParams generateLayoutParams(AttributeSet attrs) {`
        </div>
        
        <div class="line number22 index21 alt1">
          `        ``return` `new` `LinearLayout.LayoutParams(getContext(), attrs);`
        </div>
        
        <div class="line number23 index22 alt2">
          `    ``}`
        </div>
        
        <div class="line number24 index23 alt1">
          `}`
        </div>
      </div>
    </td>
  </tr>
</table>

 

这样你大概就可以理解为什么LinearLayout的子控件支持weight和gravity的设置了吧,当然我们也可以这样自定义一些属于我们 ViewGroup特有的params,这里就不详细讨论了,我们只继承MarginLayoutParams来获取子控件的margin值。

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
      
      <div class="line number4 index3 alt1">
        4
      </div>
      
      <div class="line number5 index4 alt2">
        5
      </div>
      
      <div class="line number6 index5 alt1">
        6
      </div>
      
      <div class="line number7 index6 alt2">
        7
      </div>
      
      <div class="line number8 index7 alt1">
        8
      </div>
      
      <div class="line number9 index8 alt2">
        9
      </div>
      
      <div class="line number10 index9 alt1">
        10
      </div>
      
      <div class="line number11 index10 alt2">
        11
      </div>
      
      <div class="line number12 index11 alt1">
        12
      </div>
      
      <div class="line number13 index12 alt2">
        13
      </div>
      
      <div class="line number14 index13 alt1">
        14
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `public` `class` `CustomViewGroup ``extends` `ViewGroup {`
        </div>
        
        <div class="line number2 index1 alt1">
        </div>
        
        <div class="line number3 index2 alt2">
          `    ``public` `static` `class` `LayoutParams ``extends` `ViewGroup.MarginLayoutParams {`
        </div>
        
        <div class="line number4 index3 alt1">
          `        ``public` `LayoutParams(Context c, AttributeSet attrs) {`
        </div>
        
        <div class="line number5 index4 alt2">
          `            ``super``(c, attrs);            `
        </div>
        
        <div class="line number6 index5 alt1">
          `        ``}       `
        </div>
        
        <div class="line number7 index6 alt2">
          `    ``}`
        </div>
        
        <div class="line number8 index7 alt1">
        </div>
        
        <div class="line number9 index8 alt2">
          `    ``@Override`
        </div>
        
        <div class="line number10 index9 alt1">
          `    ``public` `LayoutParams generateLayoutParams(AttributeSet attrs) {  `
        </div>
        
        <div class="line number11 index10 alt2">
          `        ``return` `new` `CustomViewGroup.LayoutParams(getContext(), attrs);  `
        </div>
        
        <div class="line number12 index11 alt1">
          `    ``}`
        </div>
        
        <div class="line number13 index12 alt2">
        </div>
        
        <div class="line number14 index13 alt1">
          `}`
        </div>
      </div>
    </td>
  </tr>
</table>

 

这样修改之后,我们就可以在onLayout()函数中获取子控件的layout_margin值了,添加了layout_margin的onLayout()函数实现如下所示:

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
      
      <div class="line number4 index3 alt1">
        4
      </div>
      
      <div class="line number5 index4 alt2">
        5
      </div>
      
      <div class="line number6 index5 alt1">
        6
      </div>
      
      <div class="line number7 index6 alt2">
        7
      </div>
      
      <div class="line number8 index7 alt1">
        8
      </div>
      
      <div class="line number9 index8 alt2">
        9
      </div>
      
      <div class="line number10 index9 alt1">
        10
      </div>
      
      <div class="line number11 index10 alt2">
        11
      </div>
      
      <div class="line number12 index11 alt1">
        12
      </div>
      
      <div class="line number13 index12 alt2">
        13
      </div>
      
      <div class="line number14 index13 alt1">
        14
      </div>
      
      <div class="line number15 index14 alt2">
        15
      </div>
      
      <div class="line number16 index15 alt1">
        16
      </div>
      
      <div class="line number17 index16 alt2">
        17
      </div>
      
      <div class="line number18 index17 alt1">
        18
      </div>
      
      <div class="line number19 index18 alt2">
        19
      </div>
      
      <div class="line number20 index19 alt1">
        20
      </div>
      
      <div class="line number21 index20 alt2">
        21
      </div>
      
      <div class="line number22 index21 alt1">
        22
      </div>
      
      <div class="line number23 index22 alt2">
        23
      </div>
      
      <div class="line number24 index23 alt1">
        24
      </div>
      
      <div class="line number25 index24 alt2">
        25
      </div>
      
      <div class="line number26 index25 alt1">
        26
      </div>
      
      <div class="line number27 index26 alt2">
        27
      </div>
      
      <div class="line number28 index27 alt1">
        28
      </div>
      
      <div class="line number29 index28 alt2">
        29
      </div>
      
      <div class="line number30 index29 alt1">
        30
      </div>
      
      <div class="line number31 index30 alt2">
        31
      </div>
      
      <div class="line number32 index31 alt1">
        32
      </div>
      
      <div class="line number33 index32 alt2">
        33
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `@Override`
        </div>
        
        <div class="line number2 index1 alt1">
          `protected` `void` `onLayout(``boolean` `changed, ``int` `left, ``int` `top, ``int` `right, ``int` `bottom) {`
        </div>
        
        <div class="line number3 index2 alt2">
        </div>
        
        <div class="line number4 index3 alt1">
          `    ``int` `mViewGroupWidth  = getMeasuredWidth();  ``//当前ViewGroup的总宽度`
        </div>
        
        <div class="line number5 index4 alt2">
          `    ``int` `mViewGroupHeight = getMeasuredHeight(); ``//当前ViewGroup的总高度`
        </div>
        
        <div class="line number6 index5 alt1">
        </div>
        
        <div class="line number7 index6 alt2">
          `    ``int` `mPainterPosX = left; ``//当前绘图光标横坐标位置`
        </div>
        
        <div class="line number8 index7 alt1">
          `    ``int` `mPainterPosY = top;  ``//当前绘图光标纵坐标位置  `
        </div>
        
        <div class="line number9 index8 alt2">
          `    `
        </div>
        
        <div class="line number10 index9 alt1">
          `    ``int` `childCount = getChildCount();        `
        </div>
        
        <div class="line number11 index10 alt2">
          `    ``for` `( ``int` `i = ````; i &lt; childCount; i++ ) {`
        </div>
        
        <div class="line number12 index11 alt1">
          `        `
        </div>
        
        <div class="line number13 index12 alt2">
          `        ``View childView = getChildAt(i);`
        </div>
        
        <div class="line number14 index13 alt1">
        </div>
        
        <div class="line number15 index14 alt2">
          `        ``int` `width  = childView.getMeasuredWidth();`
        </div>
        
        <div class="line number16 index15 alt1">
          `        ``int` `height = childView.getMeasuredHeight();             `
        </div>
        
        <div class="line number17 index16 alt2">
        </div>
        
        <div class="line number18 index17 alt1">
          `        ``CustomViewGroup.LayoutParams margins = (CustomViewGroup.LayoutParams)(childView.getLayoutParams());`
        </div>
        
        <div class="line number19 index18 alt2">
          `        `
        </div>
        
        <div class="line number20 index19 alt1">
          `        ``//ChildView占用的width  = width+leftMargin+rightMargin`
        </div>
        
        <div class="line number21 index20 alt2">
          `        ``//ChildView占用的height = height+topMargin+bottomMargin`
        </div>
        
        <div class="line number22 index21 alt1">
          `        ``//如果剩余的空间不够,则移到下一行开始位置`
        </div>
        
        <div class="line number23 index22 alt2">
          `        ``if``( mPainterPosX + width + margins.leftMargin + margins.rightMargin &gt; mViewGroupWidth ) {               `
        </div>
        
        <div class="line number24 index23 alt1">
          `            ``mPainterPosX = left; `
        </div>
        
        <div class="line number25 index24 alt2">
          `            ``mPainterPosY += height + margins.topMargin + margins.bottomMargin;`
        </div>
        
        <div class="line number26 index25 alt1">
          `        ``}                    `
        </div>
        
        <div class="line number27 index26 alt2">
          `        `
        </div>
        
        <div class="line number28 index27 alt1">
          `        ``//执行ChildView的绘制`
        </div>
        
        <div class="line number29 index28 alt2">
          `        ``childView.layout(mPainterPosX+margins.leftMargin, mPainterPosY+margins.topMargin,mPainterPosX+margins.leftMargin+width, mPainterPosY+margins.topMargin+height);`
        </div>
        
        <div class="line number30 index29 alt1">
          `        `
        </div>
        
        <div class="line number31 index30 alt2">
          `        ``mPainterPosX += width + margins.leftMargin + margins.rightMargin;`
        </div>
        
        <div class="line number32 index31 alt1">
          `    ``}       `
        </div>
        
        <div class="line number33 index32 alt2">
          `}`
        </div>
      </div>
    </td>
  </tr>
</table>

 

转自:http://ticktick.blog.51cto.com/823160/1542200

💬 评论