Android View - 布局Layout

27 篇文章 0 订阅
11 篇文章 0 订阅

Layout起布局作用,确定View的位置。当ViewGroup确定位置后,会遍历子View并调用其layout方法确定子View的位置。

View的onLayout方法

View的onLayout方法是一个空实现,因为子View不包含其他View,不需要被调用。

ViewGroup的onLayout方法

ViewGroup会先调用layout方法:

public final void layout(int l, int t, int r, int b) {  
    boolean changed = setFrame(l, t, r, b);  
    if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {  
        if (ViewDebug.TRACE_HIERARCHY) {  
            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_LAYOUT);  
        }  
        onLayout(changed, l, t, r, b);  
        mPrivateFlags &= ~LAYOUT_REQUIRED;  
    }  
    mPrivateFlags &= ~FORCE_LAYOUT;  
}  

ViewGroup的onLayout方法是一个抽象方法,由子类去实现,主要是让ViewGroup在这个方法确定每个子View的位置。

@Override  
protected abstract void onLayout(boolean changed, int l, int t, int r, int b);

我们需要关心的其实就是这个方法,以LinearLayout为例:

@Override  
protected void onLayout(boolean changed, int l, int t, int r, int b) {  
    if (mOrientation == VERTICAL) {  
        layoutVertical();  
    } else {  
        layoutHorizontal();  
    }  
}  

根据android:orientation属性给子View设置不同的位置,看layoutVertical方法代码:

void layoutVertical() {  
    final int paddingLeft = mPaddingLeft;  
    int childTop = mPaddingTop;  
    int childLeft;  
    // Where right end of child should go  
    final int width = mRight - mLeft;  
    int childRight = width - mPaddingRight;  
    // Space available for child  
    int childSpace = width - paddingLeft - mPaddingRight;  
    final int count = getVirtualChildCount();  
    final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;  
    final int minorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;  
    if (majorGravity != Gravity.TOP) {  
       switch (majorGravity) {  
           case Gravity.BOTTOM:  
               // mTotalLength contains the padding already, we add the top  
               // padding to compensate  
               childTop = mBottom - mTop + mPaddingTop - mTotalLength;  
               break;  
           case Gravity.CENTER_VERTICAL:  
               childTop += ((mBottom - mTop)  - mTotalLength) / 2;  
               break;  
       }  
    }  
    for (int i = 0; i < count; i++) {  
        final View child = getVirtualChildAt(i);  
        if (child == null) {  
            childTop += measureNullChild(i);  
        } else 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;  
            if (gravity < 0) {  
                gravity = minorGravity;  
            }  
            switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {  
                case Gravity.LEFT:  
                    childLeft = paddingLeft + lp.leftMargin;  
                    break;  
                case Gravity.CENTER_HORIZONTAL:  
                    childLeft = paddingLeft + ((childSpace - childWidth) / 2)  
                            + lp.leftMargin - lp.rightMargin;  
                    break;  
                case Gravity.RIGHT:  
                    childLeft = childRight - childWidth - lp.rightMargin;  
                    break;  
                default:  
                    childLeft = paddingLeft;  
                    break;  
            }  
            childTop += lp.topMargin;  
            setChildFrame(child, childLeft, childTop + getLocationOffset(child),  
                    childWidth, childHeight);  
            childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);  
            i += getChildrenSkipCount(child, i);  
        }  
    }  
}  

在layout时,会用到子View测量后的值,所以先测量,后布局。最后调用setChildFrame方法:

private void setChildFrame(View child, int left, int top, int width, int height) {        
    child.layout(left, top, left + width, top + height);
}

调用子View的layout方法确定位置。

我们自定义流式布局时,就需要像这样重写onLayout方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值