在这之前我首先看了网上多个版本的继承ViewGroup的方式,详细版如下:
http://blog.csdn.net/xmxkf/article/details/51500304
快捷版:
http://blog.csdn.net/huachao1001/article/details/51577291
好了,先来说说自定义ViewGroup遇到的一些问题,总的来说,继承ViewGroup和继承View差别并不是很大,只是继承ViewGroup必须重写OnLayout方法,然后OnMeasure方法测量宽和高要考虑的东西也不一样!
好啦!咱们先来说说OnLayout方法吧,这个方法中有五个参数,是用于子View摆放的位置的,l,t,r,b就相当于是子View矩形区域的上下左右,在这里还得说一下另一个方法叫做getChildCount();这个函数返回的是当前layout内的所有子控件的数量(ps:子控件内的子控件是不算的)
先上代码,再继续说:
public class MyLayout extends ViewGroup {
public MyLayout(Context context) {
super(context);
}
public MyLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
//记录当前的高度位置
int curHeight = t;
//将子View逐个摆放
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
int height = child.getMeasuredHeight();
int width = child.getMeasuredWidth();
//摆放子View,参数分别是子View矩形区域的左、上、右、下边
child.layout(l, curHeight, l + width, curHeight + height);
curHeight += height;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureChildren(widthMeasureSpec,heightMeasureSpec);
int widthMode=MeasureSpec.getMode(widthMeasureSpec);
int heightMode=MeasureSpec.getMode(heightMeasureSpec);
int width=MeasureSpec.getSize(widthMeasureSpec);
int height=MeasureSpec.getSize(heightMeasureSpec);
//返回所有子控件的数量,但不会返回子控件内子控件的数量
int childcount=getChildCount();
if (childcount==0){
setMeasuredDimension(0,0);
}else {
if (widthMode==MeasureSpec.AT_MOST&&heightMode==MeasureSpec.AT_MOST){
for (int i=0;i<childcount;i++){
View view=getChildAt(i);
// getMeasuredHeight()表示View的实际大小,getHeight()表示View在屏幕上显示的大小
height+=view.getMeasuredHeight();
width=view.getMeasuredWidth();
setMeasuredDimension(width,height);
}
}else if (widthMode==MeasureSpec.AT_MOST){
width=getMeasuredWidth();
setMeasuredDimension(width,height);
}else if (heightMode==MeasureSpec.AT_MOST){
height=getMeasuredHeight();
setMeasuredDimension(width,height);
}
}
}
}
这是仿造快捷版链接里面那个自定义的LinearLayout,功能是一样的,但是只可以垂直排列,先说一下OnMeasure方法
这个方法再ViewGroup中有三个内置方法:
measureChildren\measureChild\measureChildWithMargins
第一个measureChildren,用于测量当前所有子View的宽和高的总和;
第二个measureChild,用来测量当前某一个子View的宽和高
第三个同理,只是加上了Margin值;
现在砸门来分析一下代码:
首先继承ViewGroup,重写三个构造函数,还有Onlayout和OnMeasure方法,然后再OnMeasure中,我们使用onMesureChildren取得所有子View的宽和高,然后初始化长宽的模式和长宽大小,先判断再我们的lauout中有没有子View,如果没有的话我们将长和宽设置为0,如果有的话判断属性中用户传给我们的到底是Warp还是Match,如果长和宽都为match,那么高和宽就都等于整个屏幕的高宽度,如果包含了warp或者都为warp,则宽等于最宽的子View的宽度,高等于所有子View加起来的高度,完成了这些之后,再onlayout中我们设置子View的排列方式
首先我们记录当前的子View的高度,然后当我们新添View的时候,我们将下一个View的左坐标设置为默认的l(0),将上坐标设置为前一个View的高度,那么这个新的子View自然就在其下方,右方坐标当然就可以直接使用getmeasurewidth来获取用户自己设置的宽度,下方坐标就应该是前一个子View加上现在这个子View的共同高度,然后在循环中,我们每一次添加一个View就将获取到的第一个View的高度加上新的View的高度
以上内容纯属个人学习总结,如有错误欢迎指出