RelativeLayout,LinearLayout,FrameLayout

这三种布局都是常用的布局方式,继承自ViewGroup,它们的区别在于measure和layout过程

FrameLayout: measure过程中因为每个View都在一层,所以如果FrameLayout的宽,高没有设置固定大小或者Match_Parent,

则它的宽,高就是每个View中的最大宽,高,

Measure一次

layout过程也很简单,判断每个View的Gravity,Gravity包含两个方向: 水平方向和垂直方向的Gravity,根据Gravity来计算子View的位置。

LinearLayout: measure过程中,如果LinearLayout的宽,高没有设置固定大小或者Match_Parent,则它的宽,高就是每个View宽,高 +左右,上下margin + LineayLayout本身的上下左右Padding。

1 在第一次循环中,如果当前LinearLayout为固定大小,且子View的layout_width = 0; layout_weight > 0,那么这些view先不被测量

2 如果存在LinearLayout为固定大小,且子View的layout_width = 0; layout_weight > 0,需要进行第二次循环,测量这写view的大小

即 LinearLayout最多measure 2次,

layout过程也很简单,根据LinearLayout的方向,判断是measureHorizontal还是mearsureVertical,我们以LayoutHorizontal为例

首先根据LinearLayout本身设置的Gravity,来确定第一个view的left坐标

然后进行循环,从左向右,来判断所有view的left,top,right,bottom

 

RelativeLayout:

 因为其内部所有的view都是相对RelativeLayout或者相对其他View的布局

在measure过程中,分为2次,一次是水平关系上的measure,一次是垂直方向的measure

首先将相对关系转换成坐标,然后开始测量view,再然后,通过相对关系,以及view大小,确定view的left,top,right,bottom坐标

layout过程: 由于在measure过程中,所有view的坐标已经

 

介绍一下在上面三种Layout中的View水平居中或垂直居中的设置

1 FrameLayout

1) 如果设置了水平居中: 

switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
    //水平居中: 计算时,需要考虑到view的左, 右 margin
    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;
}

2) 如果设置了垂直居中

switch (verticalGravity) {
    case Gravity.TOP:
        childTop = parentTop + lp.topMargin;
        break;
   //垂直居中, 计算时需要考虑view的上,下margin
    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;
}

LinearLayout

如果LinearLayout为水平方向

1 如果LinearLayout设置了center_horizontal,则根据这个Gravity 计算第一个view的left坐标,然后计算每个子view的Top坐标

switch (Gravity.getAbsoluteGravity(majorGravity, layoutDirection)) {
    case Gravity.RIGHT:
        // mTotalLength contains the padding already
        childLeft = mPaddingLeft + right - left - mTotalLength;
        break;

    case Gravity.CENTER_HORIZONTAL:
        // mTotalLength contains the padding already
        childLeft = mPaddingLeft + (right - left - mTotalLength) / 2;
        break;

    case Gravity.LEFT:
    default:
        childLeft = mPaddingLeft;
        break;
}

然后判断每个view是否设置了center_vertical,如果设置了,

switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
    case Gravity.TOP:
        childTop = paddingTop + lp.topMargin;
        if (childBaseline != -1) {
            childTop += maxAscent[INDEX_TOP] - childBaseline;
        }
        break;

    //垂直居中,
    case Gravity.CENTER_VERTICAL:
        // Removed support for baseline alignment when layout_gravity or
        // gravity == center_vertical. See bug #1038483.
        // Keep the code around if we need to re-enable this feature
        // if (childBaseline != -1) {
        //     // Align baselines vertically only if the child is smaller than us
        //     if (childSpace - childHeight > 0) {
        //         childTop = paddingTop + (childSpace / 2) - childBaseline;
        //     } else {
        //         childTop = paddingTop + (childSpace - childHeight) / 2;
        //     }
        // } else {
        // childSpace为linearLayout高度减去linearLayout上 下 Padding
        childTop = paddingTop + ((childSpace - childHeight) / 2)
                + lp.topMargin - lp.bottomMargin;
        break;

    case Gravity.BOTTOM:
        childTop = childBottom - childHeight - lp.bottomMargin;
        if (childBaseline != -1) {
            int descent = child.getMeasuredHeight() - childBaseline;
            childTop -= (maxDescent[INDEX_BOTTOM] - descent);
        }
        break;
    default:
        childTop = paddingTop;
        break;
}

如果LinearLayout为垂直方向,和上面类似, 先判断垂直方向的第一个view的Top坐标,然后判断每个子view的Gravity,计算每一子view的left坐标,

LinearLayout 和 FrameLayout中,设置子view水平或垂直居中,都考虑了 Layout本身的padding以及子view的margin。

LinearLayout oritation 为horizontal是,gravity为center_vertical的情况下,子view的坐标计算:

mTop = mPaddingTop(LinearLayout的paddingTop) + (childSpace(LinearLayout的高度- (paddingTop+paddingBottom)) - childHeight) /2 + marginTop(childView) - marginBottom(ChildView)

 

 

RelativeLayout

如果view设置了layout_centerInParent 为 true,则计算其水平居中和垂直居中

//水平居中, left坐标为(RelativeLayout width - childWidth) /2
private static void centerHorizontal(View child, LayoutParams params, int myWidth) {
    int childWidth = child.getMeasuredWidth();
    
    int left = (myWidth - childWidth) / 2;

    params.mLeft = left;
    params.mRight = left + childWidth;
}

//垂直居中, left坐标为(RelativeLayout height - childHeight) /2
private static void centerVertical(View child, LayoutParams params, int myHeight) {
    int childHeight = child.getMeasuredHeight();
    int top = (myHeight - childHeight) / 2;

    params.mTop = top;
    params.mBottom = top + childHeight;
}

RelativeLayout的

垂直居中,在mearsure阶段,Relative以及将自身 padding 以及 子 view的margin,综合计算,得出 子view的高度

子view的mTop =  (RelativeLayout的 height - 子view高度(RelativeLayout - Releative的paddingtop,paddingBottom, view的marginTop,marginBotton) ) / 2

 

所以RelativeLayout一定可以居中对齐,而设置在linearLayout gravity=center_vertical 并不保证居中对齐

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值