自定义容器组件ViewGroup

 * 1 实现3个构造函数

 * 2 重写onMeasure 方法,计算子控件和自己的各种尺寸 (必须调用measureChildren)

 * 3 调用onLayout方法,对子位置进行计算,进行布局 

 *   

 *   重写方法generateLayoutParams返回MarginLayoutParams 因为可以得到控件的margin参数 

   

public class CustomImgContainer extends ViewGroup
{

	private static final String TAG = "CustomImgContainer";

	public CustomImgContainer(Context context, AttributeSet attrs, int defStyle)
	{
		super(context, attrs, defStyle);
	}

	public CustomImgContainer(Context context)
	{
		super(context);
	}

	public CustomImgContainer(Context context, AttributeSet attrs)
	{
		super(context, attrs);
	}

	/**
	 * 计算所有ChildView的宽度和高度 然后根据ChildView的计算结果,设置自己的宽和高
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		/**
		 * 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式
		 */
		int widthMode = MeasureSpec.getMode(widthMeasureSpec);
		int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
		int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

		Log.e(TAG, (heightMode == MeasureSpec.UNSPECIFIED) + "," + sizeHeight
				+ "," + getLayoutParams().height);

		// 计算出所有的childView的宽和高
		measureChildren(widthMeasureSpec, heightMeasureSpec);
		/**
		 * 记录如果是wrap_content是设置的宽和高
		 */
		int width = 0;
		int height = 0;

		int cCount = getChildCount();//得到子容器的数量

		int cWidth = 0;
		int cHeight = 0;
		MarginLayoutParams cParams = null;

		// 用于计算左边两个childView的高度
		int lHeight = 0;
		// 用于计算右边两个childView的高度,最终高度取二者之间大值
		int rHeight = 0;

		// 用于计算上边两个childView的宽度
		int tWidth = 0;
		// 用于计算下面两个childiew的宽度,最终宽度取二者之间大值
		int bWidth = 0;

		/**
		 * 根据childView计算的出的宽和高,以及设置的margin计算容器的宽和高,主要用于容器是warp_content时
		 */
		for (int i = 0; i < cCount; i++)
		{
			View childView = getChildAt(i);
			cWidth = childView.getMeasuredWidth();
			cHeight = childView.getMeasuredHeight();
			cParams = (MarginLayoutParams) childView.getLayoutParams();

			// 上面两个childView 的两个宽度+总的Margin(下面相同)
			if (i == 0 || i == 1)
			{
				tWidth += cWidth + cParams.leftMargin + cParams.rightMargin;
			}

			if (i == 2 || i == 3)//下面两个childView
			{
				bWidth += cWidth + cParams.leftMargin + cParams.rightMargin;
			}
			//左边两个
			if (i == 0 || i == 2)
			{
				lHeight += cHeight + cParams.topMargin + cParams.bottomMargin;
			}
			//右边两个
			if (i == 1 || i == 3)
			{
				rHeight += cHeight + cParams.topMargin + cParams.bottomMargin;
			}

		}
		
		width = Math.max(tWidth, bWidth); //上面两个 和下面两个 宽比较,用最大的 
		height = Math.max(lHeight, rHeight);//左边 和右边两个 宽比较,用最大的 

		/**
		 * 如果是wrap_content设置为我们计算的值
		 * 否则:直接设置为父容器计算的值
		 * //设置该ViewGroup的大小 
		 *  如果是 EXACTLY 模式(父容器能完全确定此容器的宽高),则 父容器给当前容器的大小为真正大小 
		 *  否则(wrat_content)按照自己计算的宽高 给这个容器使用
		 */
		setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth
				: width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight
				: height);
	}

	// abstract method in viewgroup
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b)
	{
		int cCount = getChildCount();
		int cWidth = 0;
		int cHeight = 0;
		MarginLayoutParams cParams = null;
		/**
		 * 遍历所有childView根据其宽和高,以及margin进行布局
		 */
		for (int i = 0; i < cCount; i++)
		{
			View childView = getChildAt(i);
			cWidth = childView.getMeasuredWidth(); 
			cHeight = childView.getMeasuredHeight();
			cParams = (MarginLayoutParams) childView.getLayoutParams();

			int cl = 0, ct = 0, cr = 0, cb = 0;

			switch (i)
			{
			case 0:
				cl = cParams.leftMargin;
				ct = cParams.topMargin;
				break;
			case 1:
				cl = getWidth() - cWidth  - cParams.rightMargin;
				ct = cParams.topMargin;

				break;
			case 2:
				cl = cParams.leftMargin;
				ct = getHeight() - cHeight - cParams.bottomMargin;
				break;
			case 3:
				cl = getWidth() - cWidth - cParams.rightMargin;
				ct = getHeight() - cHeight - cParams.bottomMargin;
				break;

			}
			cr = cl + cWidth;
			cb = cHeight + ct;
			childView.layout(cl, ct, cr, cb);
		}

	}
	/**
	 * 如果要自定义ViewGroup支持子控件的layout_margin参数,则自定义的ViewGroup类必须重载generateLayoutParams()函数,
	 * 并且在该函数中返回一个ViewGroup.MarginLayoutParams派生类对象,这样才能使用margin参数。
	 */
	@Override
	public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs)
	{
		return new MarginLayoutParams(getContext(), attrs);
	}

	@Override
	protected ViewGroup.LayoutParams generateDefaultLayoutParams()
	{
		Log.e(TAG, "generateDefaultLayoutParams");
		return new MarginLayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.MATCH_PARENT);
	}

	@Override
	protected ViewGroup.LayoutParams generateLayoutParams(
			ViewGroup.LayoutParams p)
	{
		Log.e(TAG, "generateLayoutParams p");
		return new MarginLayoutParams(p);
	}

	/*
	 * if (heightMode == MeasureSpec.UNSPECIFIED)
		{
			int tmpHeight = 0 ;
			LayoutParams lp = getLayoutParams();
			if (lp.height == LayoutParams.MATCH_PARENT)
			{
				Rect outRect = new Rect();
				getWindowVisibleDisplayFrame(outRect);
				tmpHeight = outRect.height();
			}else
			{
				tmpHeight = getLayoutParams().height ; 
			}
			height = Math.max(height, tmpHeight);

		}
	 */
}

  布局  xml 

   

<com.example.zhy_custom_viewgroup.CustomImgContainer xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#AA333333" >

    <TextView
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:background="#E5ED05"
        android:gravity="center"
        android:text="0"
        android:textColor="#FFFFFF"
        android:textSize="22sp"
        android:textStyle="bold" />

    <TextView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#00ff00"
        android:gravity="center"
        android:text="1"
        android:textColor="#FFFFFF"
        android:textSize="22sp"
        android:textStyle="bold" />

    <TextView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#ff0000"
        android:gravity="center"
        android:text="2"
        android:textColor="#FFFFFF"
        android:textSize="22sp"
        android:textStyle="bold" />

    <TextView
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:background="#0000ff"
        android:gravity="center"
        android:text="3"
        android:textColor="#FFFFFF"
        android:textSize="22sp"
        android:textStyle="bold" />

</com.example.zhy_custom_viewgroup.CustomImgContainer>

  参考:  http://blog.csdn.net/lmj623565791/article/details/38339817