这里的ViewGroup,是指他可以作为一个放置View的容器,就像LinearLayout那样,可以放一些View在这个父布局中。
1.如果此自定义的ViewGroup设置的是wrap_content,那么需要计算所有子View的宽和高,算出这些View占用的宽和高,
并且调用setMeasuredDimension 方法。
2.如果设置的是match_parent或者具体的值,则直接用MeasureSpec的值。
3.需要在onLayout中完成对其childView的位置的指定。
下面这个例子:
1.重写onMeasure方法,计算出ViewGroup的宽和高
2.重写onLayout, 确定childView的摆放位置。
这个例子你可以学到
1.一般都有遍历子孩子的方法如下:
int cCount = getChildCount();
for (int i = 0; i < cCount; i++){
View childView = getChildAt(i);
}
2.要想获取View的宽和高,一般调用这个方法:
cWidth = childView.getMeasuredWidth();
cHeight = childView.getMeasuredHeight();
3.获取ChildView距离ViewGroup的左右上下间距:
MarginLayoutParams cParams = (MarginLayoutParams) childView.getLayoutParams();
cParams.leftMargin
cParams.rightMargin
cParams.topMargin
cParams.bottomMargin
4.获取最大宽和最大高:
Math.max(tWidth, bWidth);
Math.max(lHeight, rHeight);
5.在onMeasure方法中确定ViewGroup的宽和高
/**
* 如果是wrap_content设置为我们计算的值
* 否则:直接设置为父容器计算的值
*/
setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth
: width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight
: height);
6.ViewGroup的宽和高如何获取:
getWidth()
getHeight()
7.根据childView的margin和它自身的宽和高,以及ViewGroup的宽和高,求出子view的int l, int t, int r, int b, 比如:
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.leftMargin
- cParams.rightMargin;
ct = cParams.topMargin;
break;
case 2:
cl = cParams.leftMargin;
ct = getHeight() - cHeight - cParams.bottomMargin;
break;
case 3:
cl = getWidth() - cWidth - cParams.leftMargin
- cParams.rightMargin;
ct = getHeight() - cHeight - cParams.bottomMargin;
break;
}
cr = cl + cWidth;
cb = cHeight + ct;
childView.layout(cl, ct, cr, cb);
}
下面粘贴代码
1.CustomImgContainer.java
package com.xsh.customviewstudy.group;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
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:计算
if (i == 0 || i == 1)
{
tWidth += cWidth + cParams.leftMargin + cParams.rightMargin;
}
if (i == 2 || i == 3)
{
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设置为我们计算的值
* 否则:直接设置为父容器计算的值
*/
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.leftMargin
- cParams.rightMargin;
ct = cParams.topMargin;
break;
case 2:
cl = cParams.leftMargin;
ct = getHeight() - cHeight - cParams.bottomMargin;
break;
case 3:
cl = getWidth() - cWidth - cParams.leftMargin
- cParams.rightMargin;
ct = getHeight() - cHeight - cParams.bottomMargin;
break;
}
cr = cl + cWidth;
cb = cHeight + ct;
childView.layout(cl, ct, cr, cb);
}
}
@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);
}
*/
}
2.使用activity_custom_img_container.xml
<com.xsh.customviewstudy.group.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.xsh.customviewstudy.group.CustomImgContainer>
源码参考我的github地址