1.layout总体流程和measure过程是类似的.都是在ViewRootImpl.performTraversals中调用host的方法.host的layout方法不建议子视图重写.子视图应该重写onLayout方法来实现布局过程.其实最终都是通过调用setFrame()函数来设定自己在父视图中的位置
1.png
2.View.layout函数中先调用setFrame()指定了该视图在父视图中左上右下的位置,并把这些位置保存在该视图中.然后调用onlayout()函数,VieGroup必须重写该函数对子视图进行layout.然后就是通知OnLayoutChangeListener发生了layout变化.
3.下边看下LinearLayout的onLayout过程,竖直方向上的
void layoutVertical(int left, int top, int right, int bottom) {//1.形参是该lInearLayout父视图在他的父视图中的位置.左上右下.
final int paddingLeft = mPaddingLeft;
int childTop;
int childLeft;
// Where right end of child should go
final int width = right - left; //2.父视图的宽度
int childRight = width - mPaddingRight; //3.子视图right的最大值就是父视图的宽度-paddingright
// Space available for child
int childSpace = width - paddingLeft - mPaddingRight; //4.子视图的最大宽度
final int count = getVirtualChildCount();//5.子视图的数量
final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
switch (majorGravity) { //6.根据父视图的gravity值.计算子视图的top的值.这里是竖直方向上的
case Gravity.BOTTOM:
// mTotalLength contains the padding already
childTop = mPaddingTop + bottom - top - mTotalLength;
break;
// mTotalLength contains the padding already
case Gravity.CENTER_VERTICAL:
childTop = mPaddingTop + (bottom - top - mTotalLength) / 2;
break;
case Gravity.TOP:
default:
childTop = mPaddingTop;
break;
}
for (int i = 0; i < count; i++) {//7.根据子视图的layout_gravity值.计算每个子视图在水平方向上的left值
final View child = getVirtualChildAt(i);
if (child.getVisibility() != GONE) {
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
final LinearLayout.LayoutParams lp =
(LinearLayout.LayoutParams) child.getLayoutParams();
int gravity = lp.gravity;//8因为这里取的是LayoutParams 的gravity,而LayoutParams 是父视图调用addView()添加子视图时
为子视图创建的.所以这里的值是子视图的layout_gravity属性的值,而不是子视图的gravity的值.并且,gravity也并不影响子视图的位置,它只
影响子视图中内容的位置.
if (gravity < 0) {
gravity = minorGravity;
}
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
childLeft = paddingLeft + ((childSpace - childWidth) / 2)
+ lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
childLeft = childRight - childWidth - lp.rightMargin;
break;
case Gravity.LEFT:
default:
childLeft = paddingLeft + lp.leftMargin;
break;
}
if (hasDividerBeforeChildAt(i)) {
childTop += mDividerHeight;
}
childTop += lp.topMargin;
setChildFrame(child, childLeft, childTop + getLocationOffset(child),
childWidth, childHeight);//9.为子视图设置他在父视图中的位置.这里调用了子视图的layout()方法递归layout过程.
childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
i += getChildrenSkipCount(child, i);
}
}
}
注意.任何view的layout_ 之类的属性,都是在这个view的父视图addView()时,通过调用generateLayoutParams(attr)来生成的.此时的attr就是子视图的layout_属性,换句话说.父视图为子视图创建layoutParams. 而创建layoutParams所需要的参数来自子视图自己的定义.同时这也意味着.如果你单纯的只写一个view.而不包括父视图.那么他的layout_相关的属性都不会起作用
网友评论