现在剩下Framelayout了;
直接先看onlayout:
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
layoutChildren(left, top, right, bottom, false /* no force left gravity */);
}
直接执行的是` layoutChildren(left, top, right, bottom, false /* no force left gravity */);看源码:
void layoutChildren(int left, int top, int right, int bottom,
boolean forceLeftGravity) {
//子组件数目
final int count = getChildCount();
//容器的上下左右
final int parentLeft = getPaddingLeftWithForeground();
final int parentRight = right - left - getPaddingRightWithForeground();
final int parentTop = getPaddingTopWithForeground();
final int parentBottom = bottom - top - getPaddingBottomWithForeground();
mForegroundBoundsChanged = true;
//循环开始
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
//获取布局属性
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
//宽度和高度
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
//定义左边起点和顶部起点
int childLeft;
int childTop;
//获取位置描述
int gravity = lp.gravity;
if (gravity == -1) {
//设置默认
gravity = DEFAULT_CHILD_GRAVITY;
}
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
//根据容器的左边界和右边界还有子组件的宽度计算出子组件的左边的位置
childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
if (!forceLeftGravity) {
//还是以容器的边界为开始
childLeft = parentRight - width - lp.rightMargin;
break;
}
case Gravity.LEFT:
default:
childLeft = parentLeft + lp.leftMargin;
}
switch (verticalGravity) {
case Gravity.TOP:
childTop = parentTop + lp.topMargin;
break;
case Gravity.CENTER_VERTICAL:
childTop = parentTop + (parentBottom - parentTop - height) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
childTop = parentBottom - height - lp.bottomMargin;
break;
default:
childTop = parentTop + lp.topMargin;
}
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
}
从上面代码不难看出,布局的时候,子组件之间都是共享容器的空间;因为每次计算子组件的位置的时候,都是以容器的左右上下边界来为基础,然后加上或者减去子组件本身的左右上下边距;所以Framelayout里面的组件都是一层一层堆叠的,并不存在互相拥挤的情况。
到此为止,我们通过源码分析出了Linearlayout,Relativelayout,Framelayout的布局区别。大家有兴趣的话可以再看看别的布局源码;也可以自己模仿这些自定义一个自己的ViewGroup容器。