欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

LinearLayout的onLayout()分析

程序员文章站 2022-05-09 09:53:43
/** * onLayout()函 数 中 首 先 根 据 mOrientation变 量 判 断 是 水 平 还 是 垂 直 ,如 果 是 垂 直 , 则调用 * layoutVertical()开始进行 layout 操作。 */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (mOrientation == VERTI....
 /**
     * onLayout()函 数 中 首 先 根 据 mOrientation变 量 判 断 是 水 平 还 是 垂 直 ,如 果 是 垂 直 , 则调用
     * layoutVertical()开始进行 layout 操作。
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (mOrientation == VERTICAL) {
            layoutVertical();
        } else {
            layoutHorizontal();
        }
    }

layoutVertical()过程

void layoutVertical() {
        /**
         * 1)获得子视图可用的宽度。读者可能觉得奇怪,这里是进行垂直方向上的布局,为什么却要可用
         * 的宽度,而不是可用的髙度呢?因为,就算是垂直方向,子视图本身也可以水平居中,而要居中就得知
         * 道可用的宽度是多少,从而计算出子视图左边沿的位置.
         */
        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;
        /**
         * 根据父视图中的gravity属性,决定子视图的起始位置。在默认情况下,gravity是 TOP,应用
         * 程序可以设置为BOTTOM或 者CENTER_VERTICAL,
         */
        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()循环为每一个子视图分配位置。
         * ( 1 ) 取 出 子 视 图 的LayoutParams,并 得 到 gravity的值。注 意 这 个 gravity值并不是子视图中
         * android:gravity的值,而 是 android:layout_gravity的值,关于这一点的解释见下一小节。
         * ( 2 ) 根 据 gravity的 值 确 定 水 平 方 向 上 的 起 始 位 置 , 分 为 三 种 , 分 别 是 LEFT、
         * CENTER HORIZONTAL及 RIGH T
         */
        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;
                }

                /**
                 * 调 用 setChildFrameO,该函数内部实际上就是调用child.layout()为子视图设置布局位置。
                 * 至此, LinearLayout就完成了为所包含的子视图分配布局位置的过程。
                 */
                childTop += lp.topMargin;
                setChildFrame(child, childLeft, childTop + getLocationOffset(child),
                        childWidth, childHeight);
                childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);

                i += getChildrenSkipCount(child, i);
            }
        }
    }

本文地址:https://blog.csdn.net/CTO_1649900265/article/details/107600228