(自定义ViewGroup)
自定义布局主要是重写两个方法:
- onMeasure() 这个是写自定义容器的大小。
- onLayout() 这个是写子元素的布局。 我自己写了一个自定义布局,是顺序填充会延对角线进行排列。
3.1onMeasure()
@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); // 计算出所有的childView的宽和高 measureChildren(widthMeasureSpec, heightMeasureSpec); /** * width和height是当wrap_content时使用的属性。 */ int width = 0; int height = 0; int cCount = getChildCount(); int cWidth = 0; int cHeight = 0; /** * 在这里计算当wrap_content时,布局的大小。 */ for (int i = 0; i < cCount; i++) { View childView = getChildAt(i); cWidth = childView.getMeasuredWidth(); cHeight = childView.getMeasuredHeight(); width += cWidth; height += cHeight; } /** * 如果是wrap_content设置为我们计算的值 * 否则:直接设置为父容器计算的值 */ setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth : width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight : height); }
首先要说一下布局计算模式,即最后的EXACTLY。一共有三种计算模式:
- MeasureSpec.EXACTLY:精确尺寸,相当于具体数值和match_parent。
- MeasureSpec.AT_MOST:最大尺寸,相当于 warp_content。
- MeasureSpec.UNSPECIFIED:未指定尺寸,这种情况不多,一般用于AdapterView。
最后的设定大小时,如果是精确尺寸就是用sizeWidth即获取的尺寸,如果是最大尺寸就是要我们自己计算的那个尺寸了。
onMeasure()最主要的功能就是计算wrap_content的尺寸和设置尺寸。 我将这个方法称为“建画布”,先建了画布才能在上面绘图嘛。3.2 onLayout()
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int cCount = getChildCount(); /** * 遍历所有childView根据其宽和高,以及margin进行布局 */ for (int i = 0; i < cCount; i++) { View childView = getChildAt(i); r = l + childView.getMeasuredWidth(); b = t + childView.getMeasuredHeight(); childView.layout(l, t, r, b); l += childView.getMeasuredWidth(); t += childView.getMeasuredHeight(); } }
这个方法的作用是设置摆放子元素的位置。其中onLayout()传入的l、t、r、b分别是这样
- l,t分别对应子元素左上角的left,top坐标
- r,b分别对应子元素右下角的right,bottom坐标
并且可以使用childview.getMeasuredWidth()和childView.getMeasureHeight()得到子元素的宽和高。
这样就可以来对每个子元素进行布局了。 我称这个方法为“定位置”。定完位置后那么子元素就被放到了我们想要的地方。 这样一个自定义ViewGroup就可以使用了。 xml文件如下:最后效果如图: