前面说过Linearlayout,现在研究下Relativelayout的排版源码实现;
首先还是找到onlayout源码:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// The layout has actually already been performed and the positions
// cached. Apply the cached values to the children.
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
RelativeLayout.LayoutParams st =
(RelativeLayout.LayoutParams) child.getLayoutParams();
child.layout(st.mLeft, st.mTop, st.mRight, st.mBottom);
}
}
}
发现不对,因为这个里面貌似没有做关于排版子位置的逻辑;现在在仔细想想,Relativelayout确实没有对子布局做什么排版。所以的相对位置貌似都是在子组件中进行设置的;好,那么仔细想想,子组件对相对位置的排版貌似影响着子组件的本身大小;
现在确认了,那么一定是在计算子组件大小之前对子组件的相对位置进行了处理。好了,我们知道是在onMeasure里面进行计算子组件大小的;现在我们看这个方法:
部分代码片段:
..........
applyHorizontalSizeRules(params, myWidth, rules);
measureChildHorizontal(child, params, myWidth, myHeight);
..........
applyVerticalSizeRules(params, myHeight);
measureChild(child, params, myWidth, myHeight);
先分析这两队方法:
private void applyHorizontalSizeRules(LayoutParams childParams, int myWidth, int[] rules) {
RelativeLayout.LayoutParams anchorParams;
//设置初始值
childParams.mLeft = VALUE_NOT_SET;
childParams.mRight = VALUE_NOT_SET;
//获取layout_toLeftOf属性
anchorParams = getRelatedViewParams(rules, LEFT_OF);
if (anchorParams != null) {
//假设组件B设置为在组件A的左边;那么B的右边界=A的左边界-A左内边距-B右内边距;这个逻辑关系大家在纸上画一下就好;
childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin +
childParams.rightMargin);
} else if (childParams.alignWithParent && rules[LEFT_OF] != 0) {
if (myWidth >= 0) {
//得出组件的右边界
childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
}
}
//同样,得到android:layout_toRightOf属性
anchorParams = getRelatedViewParams(rules, RIGHT_OF);
if (anchorParams != null) {
//自己分析。。。
childParams.mLeft = anchorParams.mRight + (anchorParams.rightMargin +
childParams.leftMargin);
} else if (childParams.alignWithParent && rules[RIGHT_OF] != 0) {
childParams.mLeft = mPaddingLeft + childParams.leftMargin;
}
//得到android:layout_alignLeft属性
anchorParams = getRelatedViewParams(rules, ALIGN_LEFT);
if (anchorParams != null) {
//进行左对齐操作
childParams.mLeft = anchorParams.mLeft + childParams.leftMargin;
} else if (childParams.alignWithParent && rules[ALIGN_LEFT] != 0) {
childParams.mLeft = mPaddingLeft + childParams.leftMargin;
}
//得到android:layout_alignRight属性
anchorParams = getRelatedViewParams(rules, ALIGN_RIGHT);
if (anchorParams != null) {
//进行右对齐操作
childParams.mRight = anchorParams.mRight - childParams.rightMargin;
} else if (childParams.alignWithParent && rules[ALIGN_RIGHT] != 0) {
if (myWidth >= 0) {
childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
}
}
//对android:layout_alignParentLeft进行处理,即将自己置于父容器的左边
if (0 != rules[ALIGN_PARENT_LEFT]) {
childParams.mLeft = mPaddingLeft + childParams.leftMargin;
}
//将自己置于父容器的右边
if (0 != rules[ALIGN_PARENT_RIGHT]) {
if (myWidth >= 0) {
childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
}
}
}
看完了这段代码;大概就知道这个方法是计算组件左边界和右边界的值了;
因此也就知道
applyVerticalSizeRules(params, myHeight);
可能是计算组件顶部和底部边界的方法了。这里就不在分析了。因为逻辑和上面的差不多。