view-layout过程

1.layout总体流程和measure过程是类似的.都是在ViewRootImpl.performTraversals中调用host的方法.host的layout方法不建议子视图重写.子视图应该重写onLayout方法来实现布局过程.其实最终都是通过调用setFrame()函数来设定自己在父视图中的位置


view-layout过程_第1张图片
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_相关的属性都不会起作用

你可能感兴趣的:(view-layout过程)