RelativeLayout和LinearLayout性能比较 相对布局和线性布局的性能比较

Android中常见五种布局管理器——RelativeLayout、LinearLayout、FrameLayout、TableLayout、GridLayout 布局管理器 Android提供五种布局管理器: 1.相对布局管理器(RelativeLayout):通过相对定位的方式来控制组件的摆放位置。 2.线性布局管理器(LinearLayout):是指在水平或者垂直方向上依次摆放组件。 3.帧布局管理器(FrameLayout):没有任何定位方式,默认情况下,所有的组件都会摆放在容器的左上角,逐个覆盖。 4.表格布局管理器(TableLayout):使用表格的方式按行、列来摆放组件。 5.绝对布局管理器(AbsoluteLayout):通过绝对定位(x 阅读详情

RelativeLayout和LinearLayout性能比较
相对布局和线性布局的性能比较
【转载请注明出处】 :http://blog.youkuaiyun.com/guyuealian/article/details/52162774  

     看到几篇关于RelativeLayout和LinearLayout性能分析的博客,写的相当不错,这里在大神的基础上,增加了部分内容
     RelativeLayout和LinearLayout是Android中常用的布局,两者的使用会极大的影响程序生成每一帧的性能,因此,正确的使用它们是提升程序性能的重要工作。记得以前,较低的SDK版本新建Android项目时,默认的布局文件是采用线性布局LinearLayout,但现在自动生成的布局文件都是RelativeLayout,或许你会认为这是IDE的默认设置问题,其实不然,这由 android-sdk\tools\templates\activities\BlankActivity\root\res\layout\activity_simple.xml.ftl 这个文件事先就定好了的,也就是说这是Google的选择,而非IDE的选择。那SDK为什么会默认给开发者新建一个默认的RelativeLayout布局呢?<-----原因见最后小结
     当然是因为RelativeLayout的性能更优,性能至上嘛。但是我们再看看默认新建的这个RelativeLayout的父容器,也就是当前窗口的顶级View——DecorView,它却是个垂直方向的LinearLayout,上面是标题栏,下面是内容栏。那么问题来了,Google为什么给开发者默认新建了个RelativeLayout,而自己却偷偷用了个LinearLayout,到底谁的性能更高,开发者该怎么选择呢?
       下面将通过分析它们的源码来探讨其View绘制性能,并得出其正确的使用方法。

一、View的一些基本工作原理

      先通过几个问题,简单的了解写android中View的工作原理吧。
(1)View是什么?
    简单来说,View是Android系统在屏幕上的视觉呈现,也就是说你在手机屏幕上看到的东西都是View。
(2)View是怎么绘制出来的?
    View的绘制流程是从ViewRoot的performTraversals()方法开始,依次经过measure(),layout()和draw()三个过程才最终将一个View绘制出来。
(3)View是怎么呈现在界面上的?
    Android中的视图都是通过Window来呈现的,不管Activity、Dialog还是Toast它们都有一个Window,然后通过WindowManager来管理View。Window和顶级View——DecorView的通信是依赖ViewRoot完成的。
(4)View和ViewGroup什么区别?
    不管简单的Button和TextView还是复杂的RelativeLayout和ListView,他们的共同基类都是View。所以说,View是一种界面层控件的抽象,他代表了一个控件。那ViewGroup是什么东西,它可以被翻译成控件组,即一组View。ViewGroup也是继承View,这就意味着View本身可以是单个控件,也可以是多个控件组成的控件组。根据这个理论,Button显然是个View,而RelativeLayout不但是一个View还可以是一个ViewGroup,而ViewGroup内部是可以有子View的,这个子View同样也可能是ViewGroup,以此类推。

二、RelativeLayout和LinearLayout性能PK

       基于以上原理和大背景,我们要探讨的性能问题,说的简单明了一点就是:当RelativeLayout和LinearLayout分别作为ViewGroup,表达相同布局时绘制在屏幕上时谁更快一点。上面已经简单说了View的绘制,从ViewRoot的performTraversals()方法开始依次调用perfromMeasure、performLayout和performDraw这三个方法。这三个方法分别完成顶级View的measure、layout和draw三大流程,其中perfromMeasure会调用measure,measure又会调用onMeasure,在onMeasure方法中则会对所有子元素进行measure,这个时候measure流程就从父容器传递到子元素中了,这样就完成了一次measure过程,接着子元素会重复父容器的measure,如此反复就完成了整个View树的遍历。同理,performLayout和performDraw也分别完成perfromMeasure类似的流程。通过这三大流程,分别遍历整棵View树,就实现了Measure,Layout,Draw这一过程,View就绘制出来了。那么我们就分别来追踪下RelativeLayout和LinearLayout这三大流程的执行耗时。
如下图,我们分别用两用种方式简单的实现布局测试下


LinearLayout
Measure:0.738ms
Layout:0.176ms
draw:7.655ms
RelativeLayout
Measure:2.280ms
Layout:0.153ms
draw:7.696ms
    从这个数据来看无论使用RelativeLayout还是LinearLayout,layout和draw的过程两者相差无几,考虑到误差的问题,几乎可以认为两者不分伯仲,关键是Measure的过程RelativeLayout却比LinearLayout慢了一大截。
(1)RelativeLayout的onMeasure()方法

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  2.     if (mDirtyHierarchy) {  
  3.         mDirtyHierarchy = false;  
  4.         sortChildren();  
  5.     }  
  6.   
  7.     int myWidth = -1;  
  8.     int myHeight = -1;  
  9.   
  10.     int width = 0;  
  11.     int height = 0;  
  12.   
  13.     final int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
  14.     final int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
  15.     final int widthSize = MeasureSpec.getSize(widthMeasureSpec);  
  16.     final int heightSize = MeasureSpec.getSize(heightMeasureSpec);  
  17.   
  18.     // Record our dimensions if they are known;  
  19.     if (widthMode != MeasureSpec.UNSPECIFIED) {  
  20.         myWidth = widthSize;  
  21.     }  
  22.   
  23.     if (heightMode != MeasureSpec.UNSPECIFIED) {  
  24.         myHeight = heightSize;  
  25.     }  
  26.   
  27.     if (widthMode == MeasureSpec.EXACTLY) {  
  28.         width = myWidth;  
  29.     }  
  30.   
  31.     if (heightMode == MeasureSpec.EXACTLY) {  
  32.         height = myHeight;  
  33.     }  
  34.   
  35.     mHasBaselineAlignedChild = false;  
  36.   
  37.     View ignore = null;  
  38.     int gravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;  
  39.     final boolean horizontalGravity = gravity != Gravity.START && gravity != 0;  
  40.     gravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;  
  41.     final boolean verticalGravity = gravity != Gravity.TOP && gravity != 0;  
  42.   
  43.     int left = Integer.MAX_VALUE;  
  44.     int top = Integer.MAX_VALUE;  
  45.     int right = Integer.MIN_VALUE;  
  46.     int bottom = Integer.MIN_VALUE;  
  47.   
  48.     boolean offsetHorizontalAxis = false;  
  49.     boolean offsetVerticalAxis = false;  
  50.   
  51.     if ((horizontalGravity || verticalGravity) && mIgnoreGravity != View.NO_ID) {  
  52.         ignore = findViewById(mIgnoreGravity);  
  53.     }  
  54.   
  55.     final boolean isWrapContentWidth = widthMode != MeasureSpec.EXACTLY;  
  56.     final boolean isWrapContentHeight = heightMode != MeasureSpec.EXACTLY;  
  57.   
  58.     // We need to know our size for doing the correct computation of children positioning in RTL  
  59.     // mode but there is no practical way to get it instead of running the code below.  
  60.     // So, instead of running the code twice, we just set the width to a "default display width"  
  61.     // before the computation and then, as a last pass, we will update their real position with  
  62.     // an offset equals to "DEFAULT_WIDTH - width".  
  63.     final int layoutDirection = getLayoutDirection();  
  64.     if (isLayoutRtl() && myWidth == -1) {  
  65.         myWidth = DEFAULT_WIDTH;  
  66.     }  
  67.   
  68.     View[] views = mSortedHorizontalChildren;  
  69.     int count = views.length;  
  70.   
  71.     for (int i = 0; i < count; i++) {  
  72.         View child = views[i];  
  73.         if (child.getVisibility() != GONE) {  
  74.             LayoutParams params = (LayoutParams) child.getLayoutParams();  
  75.             int[] rules = params.getRules(layoutDirection);  
  76.   
  77.             applyHorizontalSizeRules(params, myWidth, rules);  
  78.             measureChildHorizontal(child, params, myWidth, myHeight);  
  79.   
  80.             if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) {  
  81.                 offsetHorizontalAxis = true;  
  82.             }  
  83.         }  
  84.     }  
  85.   
  86.     views = mSortedVerticalChildren;  
  87.     count = views.length;  
  88.     final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;  
  89.   
  90.     for (int i = 0; i < count; i++) {  
  91.         View child = views[i];  
  92.         if (child.getVisibility() != GONE) {  
  93.             LayoutParams params = (LayoutParams) child.getLayoutParams();  
  94.               
  95.             applyVerticalSizeRules(params, myHeight);  
  96.             measureChild(child, params, myWidth, myHeight);  
  97.             if (positionChildVertical(child, params, myHeight, isWrapContentHeight)) {  
  98.                 offsetVerticalAxis = true;  
  99.             }  
  100.   
  101.             if (isWrapContentWidth) {  
  102.                 if (isLayoutRtl()) {  
  103.                     if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {  
  104.                         width = Math.max(width, myWidth - params.mLeft);  
  105.                     } else {  
  106.                         width = Math.max(width, myWidth - params.mLeft - params.leftMargin);  
  107.                     }  
  108.                 } else {  
  109.                     if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {  
  110.                         width = Math.max(width, params.mRight);  
  111.                     } else {  
  112.                         width = Math.max(width, params.mRight + params.rightMargin);  
  113.                     }  
  114.                 }  
  115.             }  
  116.   
  117.             if (isWrapContentHeight) {  
  118.                 if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {  
  119.                     height = Math.max(height, params.mBottom);  
  120.                 } else {  
  121.                     height = Math.max(height, params.mBottom + params.bottomMargin);  
  122.                 }  
  123.             }  
  124.   
  125.             if (child != ignore || verticalGravity) {  
  126.                 left = Math.min(left, params.mLeft - params.leftMargin);  
  127.                 top = Math.min(top, params.mTop - params.topMargin);  
  128.             }  
  129.   
  130.             if (child != ignore || horizontalGravity) {  
  131.                 right = Math.max(right, params.mRight + params.rightMargin);  
  132.                 bottom = Math.max(bottom, params.mBottom + params.bottomMargin);  
  133.             }  
  134.         }  
  135.     }  
  136.   
  137.     if (mHasBaselineAlignedChild) {  
  138.         for (int i = 0; i < count; i++) {  
  139.             View child = getChildAt(i);  
  140.             if (child.getVisibility() != GONE) {  
  141.                 LayoutParams params = (LayoutParams) child.getLayoutParams();  
  142.                 alignBaseline(child, params);  
  143.   
  144.                 if (child != ignore || verticalGravity) {  
  145.                     left = Math.min(left, params.mLeft - params.leftMargin);  
  146.                     top = Math.min(top, params.mTop - params.topMargin);  
  147.                 }  
  148.   
  149.                 if (child != ignore || horizontalGravity) {  
  150.                     right = Math.max(right, params.mRight + params.rightMargin);  
  151.                     bottom = Math.max(bottom, params.mBottom + params.bottomMargin);  
  152.                 }  
  153.             }  
  154.         }  
  155.     }  
  156.   
  157.     if (isWrapContentWidth) {  
  158.         // Width already has left padding in it since it was calculated by looking at  
  159.         // the right of each child view  
  160.         width += mPaddingRight;  
  161.   
  162.         if (mLayoutParams != null && mLayoutParams.width >= 0) {  
  163.             width = Math.max(width, mLayoutParams.width);  
  164.         }  
  165.   
  166.         width = Math.max(width, getSuggestedMinimumWidth());  
  167.         width = resolveSize(width, widthMeasureSpec);  
  168.   
  169.         if (offsetHorizontalAxis) {  
  170.             for (int i = 0; i < count; i++) {  
  171.                 View child = getChildAt(i);  
  172.                 if (child.getVisibility() != GONE) {  
  173.                     LayoutParams params = (LayoutParams) child.getLayoutParams();  
  174.                     final int[] rules = params.getRules(layoutDirection);  
  175.                     if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) {  
  176.                         centerHorizontal(child, params, width);  
  177.                     } else if (rules[ALIGN_PARENT_RIGHT] != 0) {  
  178.                         final int childWidth = child.getMeasuredWidth();  
  179.                         params.mLeft = width - mPaddingRight - childWidth;  
  180.                         params.mRight = params.mLeft + childWidth;  
  181.                     }  
  182.                 }  
  183.             }  
  184.         }  
  185.     }  
  186.   
  187.     if (isWrapContentHeight) {  
  188.         // Height already has top padding in it since it was calculated by looking at  
  189.         // the bottom of each child view  
  190.         height += mPaddingBottom;  
  191.   
  192.         if (mLayoutParams != null && mLayoutParams.height >= 0) {  
  193.             height = Math.max(height, mLayoutParams.height);  
  194.         }  
  195.   
  196.         height = Math.max(height, getSuggestedMinimumHeight());  
  197.         height = resolveSize(height, heightMeasureSpec);  
  198.   
  199.         if (offsetVerticalAxis) {  
  200.             for (int i = 0; i < count; i++) {  
  201.                 View child = getChildAt(i);  
  202.                 if (child.getVisibility() != GONE) {  
  203.                     LayoutParams params = (LayoutParams) child.getLayoutParams();  
  204.                     final int[] rules = params.getRules(layoutDirection);  
  205.                     if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) {  
  206.                         centerVertical(child, params, height);  
  207.                     } else if (rules[ALIGN_PARENT_BOTTOM] != 0) {  
  208.                         final int childHeight = child.getMeasuredHeight();  
  209.                         params.mTop = height - mPaddingBottom - childHeight;  
  210.                         params.mBottom = params.mTop + childHeight;  
  211.                     }  
  212.                 }  
  213.             }  
  214.         }  
  215.     }  
  216.   
  217.     if (horizontalGravity || verticalGravity) {  
  218.         final Rect selfBounds = mSelfBounds;  
  219.         selfBounds.set(mPaddingLeft, mPaddingTop, width - mPaddingRight,  
  220.                 height - mPaddingBottom);  
  221.   
  222.         final Rect contentBounds = mContentBounds;  
  223.         Gravity.apply(mGravity, right - left, bottom - top, selfBounds, contentBounds,  
  224.                 layoutDirection);  
  225.   
  226.         final int horizontalOffset = contentBounds.left - left;  
  227.         final int verticalOffset = contentBounds.top - top;  
  228.         if (horizontalOffset != 0 || verticalOffset != 0) {  
  229.             for (int i = 0; i < count; i++) {  
  230.                 View child = getChildAt(i);  
  231.                 if (child.getVisibility() != GONE && child != ignore) {  
  232.                     LayoutParams params = (LayoutParams) child.getLayoutParams();  
  233.                     if (horizontalGravity) {  
  234.                         params.mLeft += horizontalOffset;  
  235.                         params.mRight += horizontalOffset;  
  236.                     }  
  237.                     if (verticalGravity) {  
  238.                         params.mTop += verticalOffset;  
  239.                         params.mBottom += verticalOffset;  
  240.                     }  
  241.                 }  
  242.             }  
  243.         }  
  244.     }  
  245.   
  246.     if (isLayoutRtl()) {  
  247.         final int offsetWidth = myWidth - width;  
  248.         for (int i = 0; i < count; i++) {  
  249.             View child = getChildAt(i);  
  250.             if (child.getVisibility() != GONE) {  
  251.                 LayoutParams params = (LayoutParams) child.getLayoutParams();  
  252.                 params.mLeft -= offsetWidth;  
  253.                 params.mRight -= offsetWidth;  
  254.             }  
  255.         }  
  256.   
  257.     }  
  258.   
  259.     setMeasuredDimension(width, height);  
  260. }  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mDirtyHierarchy) {
            mDirtyHierarchy = false;
            sortChildren();
        }

        int myWidth = -1;
        int myHeight = -1;

        int width = 0;
        int height = 0;

        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        // Record our dimensions if they are known;
        if (widthMode != MeasureSpec.UNSPECIFIED) {
            myWidth = widthSize;
        }

        if (heightMode != MeasureSpec.UNSPECIFIED) {
            myHeight = heightSize;
        }

        if (widthMode == MeasureSpec.EXACTLY) {
            width = myWidth;
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            height = myHeight;
        }

        mHasBaselineAlignedChild = false;

        View ignore = null;
        int gravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
        final boolean horizontalGravity = gravity != Gravity.START && gravity != 0;
        gravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
        final boolean verticalGravity = gravity != Gravity.TOP && gravity != 0;

        int left = Integer.MAX_VALUE;
        int top = Integer.MAX_VALUE;
        int right = Integer.MIN_VALUE;
        int bottom = Integer.MIN_VALUE;

        boolean offsetHorizontalAxis = false;
        boolean offsetVerticalAxis = false;

        if ((horizontalGravity || verticalGravity) && mIgnoreGravity != View.NO_ID) {
            ignore = findViewById(mIgnoreGravity);
        }

        final boolean isWrapContentWidth = widthMode != MeasureSpec.EXACTLY;
        final boolean isWrapContentHeight = heightMode != MeasureSpec.EXACTLY;

        // We need to know our size for doing the correct computation of children positioning in RTL
        // mode but there is no practical way to get it instead of running the code below.
        // So, instead of running the code twice, we just set the width to a "default display width"
        // before the computation and then, as a last pass, we will update their real position with
        // an offset equals to "DEFAULT_WIDTH - width".
        final int layoutDirection = getLayoutDirection();
        if (isLayoutRtl() && myWidth == -1) {
            myWidth = DEFAULT_WIDTH;
        }

        View[] views = mSortedHorizontalChildren;
        int count = views.length;

        for (int i = 0; i < count; i++) {
            View child = views[i];
            if (child.getVisibility() != GONE) {
                LayoutParams params = (LayoutParams) child.getLayoutParams();
                int[] rules = params.getRules(layoutDirection);

                applyHorizontalSizeRules(params, myWidth, rules);
                measureChildHorizontal(child, params, myWidth, myHeight);

                if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) {
                    offsetHorizontalAxis = true;
                }
            }
        }

        views = mSortedVerticalChildren;
        count = views.length;
        final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;

        for (int i = 0; i < count; i++) {
            View child = views[i];
            if (child.getVisibility() != GONE) {
                LayoutParams params = (LayoutParams) child.getLayoutParams();
                
                applyVerticalSizeRules(params, myHeight);
                measureChild(child, params, myWidth, myHeight);
                if (positionChildVertical(child, params, myHeight, isWrapContentHeight)) {
                    offsetVerticalAxis = true;
                }

                if (isWrapContentWidth) {
                    if (isLayoutRtl()) {
                        if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
                            width = Math.max(width, myWidth - params.mLeft);
                        } else {
                            width = Math.max(width, myWidth - params.mLeft - params.leftMargin);
                        }
                    } else {
                        if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
                            width = Math.max(width, params.mRight);
                        } else {
                            width = Math.max(width, params.mRight + params.rightMargin);
                        }
                    }
                }

                if (isWrapContentHeight) {
                    if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
                        height = Math.max(height, params.mBottom);
                    } else {
                        height = Math.max(height, params.mBottom + params.bottomMargin);
                    }
                }

                if (child != ignore || verticalGravity) {
                    left = Math.min(left, params.mLeft - params.leftMargin);
                    top = Math.min(top, params.mTop - params.topMargin);
                }

                if (child != ignore || horizontalGravity) {
                    right = Math.max(right, params.mRight + params.rightMargin);
                    bottom = Math.max(bottom, params.mBottom + params.bottomMargin);
                }
            }
        }

        if (mHasBaselineAlignedChild) {
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() != GONE) {
                    LayoutParams params = (LayoutParams) child.getLayoutParams();
                    alignBaseline(child, params);

                    if (child != ignore || verticalGravity) {
                        left = Math.min(left, params.mLeft - params.leftMargin);
                        top = Math.min(top, params.mTop - params.topMargin);
                    }

                    if (child != ignore || horizontalGravity) {
                        right = Math.max(right, params.mRight + params.rightMargin);
                        bottom = Math.max(bottom, params.mBottom + params.bottomMargin);
                    }
                }
            }
        }

        if (isWrapContentWidth) {
            // Width already has left padding in it since it was calculated by looking at
            // the right of each child view
            width += mPaddingRight;

            if (mLayoutParams != null && mLayoutParams.width >= 0) {
                width = Math.max(width, mLayoutParams.width);
            }

            width = Math.max(width, getSuggestedMinimumWidth());
            width = resolveSize(width, widthMeasureSpec);

            if (offsetHorizontalAxis) {
                for (int i = 0; i < count; i++) {
                    View child = getChildAt(i);
                    if (child.getVisibility() != GONE) {
                        LayoutParams params = (LayoutParams) child.getLayoutParams();
                        final int[] rules = params.getRules(layoutDirection);
                        if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) {
                            centerHorizontal(child, params, width);
                        } else if (rules[ALIGN_PARENT_RIGHT] != 0) {
                            final int childWidth = child.getMeasuredWidth();
                            params.mLeft = width - mPaddingRight - childWidth;
                            params.mRight = params.mLeft + childWidth;
                        }
                    }
                }
            }
        }

        if (isWrapContentHeight) {
            // Height already has top padding in it since it was calculated by looking at
            // the bottom of each child view
            height += mPaddingBottom;

            if (mLayoutParams != null && mLayoutParams.height >= 0) {
                height = Math.max(height, mLayoutParams.height);
            }

            height = Math.max(height, getSuggestedMinimumHeight());
            height = resolveSize(height, heightMeasureSpec);

            if (offsetVerticalAxis) {
                for (int i = 0; i < count; i++) {
                    View child = getChildAt(i);
                    if (child.getVisibility() != GONE) {
                        LayoutParams params = (LayoutParams) child.getLayoutParams();
                        final int[] rules = params.getRules(layoutDirection);
                        if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) {
                            centerVertical(child, params, height);
                        } else if (rules[ALIGN_PARENT_BOTTOM] != 0) {
                            final int childHeight = child.getMeasuredHeight();
                            params.mTop = height - mPaddingBottom - childHeight;
                            params.mBottom = params.mTop + childHeight;
                        }
                    }
                }
            }
        }

        if (horizontalGravity || verticalGravity) {
            final Rect selfBounds = mSelfBounds;
            selfBounds.set(mPaddingLeft, mPaddingTop, width - mPaddingRight,
                    height - mPaddingBottom);

            final Rect contentBounds = mContentBounds;
            Gravity.apply(mGravity, right - left, bottom - top, selfBounds, contentBounds,
                    layoutDirection);

            final int horizontalOffset = contentBounds.left - left;
            final int verticalOffset = contentBounds.top - top;
            if (horizontalOffset != 0 || verticalOffset != 0) {
                for (int i = 0; i < count; i++) {
                    View child = getChildAt(i);
                    if (child.getVisibility() != GONE && child != ignore) {
                        LayoutParams params = (LayoutParams) child.getLayoutParams();
                        if (horizontalGravity) {
                            params.mLeft += horizontalOffset;
                            params.mRight += horizontalOffset;
                        }
                        if (verticalGravity) {
                            params.mTop += verticalOffset;
                            params.mBottom += verticalOffset;
                        }
                    }
                }
            }
        }

        if (isLayoutRtl()) {
            final int offsetWidth = myWidth - width;
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() != GONE) {
                    LayoutParams params = (LayoutParams) child.getLayoutParams();
                    params.mLeft -= offsetWidth;
                    params.mRight -= offsetWidth;
                }
            }

        }

        setMeasuredDimension(width, height);
    }

     根据上述关键代码,RelativeLayout分别对所有子View进行两次measure,横向纵向分别进行一次,这是为什么呢?首先RelativeLayout中子View的排列方式是基于彼此的依赖关系,而这个依赖关系可能和布局中View的顺序并不相同,在确定每个子View的位置的时候,需要先给所有的子View排序一下。又因为RelativeLayout允许A,B 2个子View,横向上B依赖A,纵向上A依赖B。所以需要横向纵向分别进行一次排序测量。 mSortedHorizontalChildren和mSortedVerticalChildren是分别对水平方向的子控件和垂直方向的子控件进行排序后的View数组。

(2)LinearLayout的onMeasure()方法

  1. @Override  
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  3.     if (mOrientation == VERTICAL) {  
  4.         measureVertical(widthMeasureSpec, heightMeasureSpec);  
  5.     } else {  
  6.         measureHorizontal(widthMeasureSpec, heightMeasureSpec);  
  7.     }  
  8. }  
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mOrientation == VERTICAL) {
            measureVertical(widthMeasureSpec, heightMeasureSpec);
        } else {
            measureHorizontal(widthMeasureSpec, heightMeasureSpec);
        }
    }

      与RelativeLayout相比LinearLayout的measure就简单的多,只需判断线性布局是水平布局还是垂直布局即可,然后才进行测量:

  1. /** 
  2.  * Measures the children when the orientation of this LinearLayout is set 
  3.  * to {@link #VERTICAL}. 
  4.  * 
  5.  * @param widthMeasureSpec Horizontal space requirements as imposed by the parent. 
  6.  * @param heightMeasureSpec Vertical space requirements as imposed by the parent. 
  7.  * 
  8.  * @see #getOrientation() 
  9.  * @see #setOrientation(int) 
  10.  * @see #onMeasure(int, int) 
  11.  */  
  12. void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {  
  13.     mTotalLength = 0;  
  14.     int maxWidth = 0;  
  15.     int childState = 0;  
  16.     int alternativeMaxWidth = 0;  
  17.     int weightedMaxWidth = 0;  
  18.     boolean allFillParent = true;  
  19.     float totalWeight = 0;  
  20.   
  21.     final int count = getVirtualChildCount();  
  22.       
  23.     final int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
  24.     final int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
  25.   
  26.     boolean matchWidth = false;  
  27.     boolean skippedMeasure = false;  
  28.   
  29.     final int baselineChildIndex = mBaselineAlignedChildIndex;          
  30.     final boolean useLargestChild = mUseLargestChild;  
  31.   
  32.     int largestChildHeight = Integer.MIN_VALUE;  
  33.   
  34.     // See how tall everyone is. Also remember max width.  
  35.     for (int i = 0; i < count; ++i) {  
  36.         final View child = getVirtualChildAt(i);  
  37.   
  38.         if (child == null) {  
  39.             mTotalLength += measureNullChild(i);  
  40.             continue;  
  41.         }  
  42.   
  43.         if (child.getVisibility() == View.GONE) {  
  44.            i += getChildrenSkipCount(child, i);  
  45.            continue;  
  46.         }  
  47.   
  48.         if (hasDividerBeforeChildAt(i)) {  
  49.             mTotalLength += mDividerHeight;  
  50.         }  
  51.   
  52.         LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();  
  53.   
  54.         totalWeight += lp.weight;  
  55.           
  56.         if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {  
  57.             // Optimization: don't bother measuring children who are going to use  
  58.             // leftover space. These views will get measured again down below if  
  59.             // there is any leftover space.  
  60.             final int totalLength = mTotalLength;  
  61.             mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);  
  62.             skippedMeasure = true;  
  63.         } else {  
  64.             int oldHeight = Integer.MIN_VALUE;  
  65.   
  66.             if (lp.height == 0 && lp.weight > 0) {  
  67.                 // heightMode is either UNSPECIFIED or AT_MOST, and this  
  68.                 // child wanted to stretch to fill available space.  
  69.                 // Translate that to WRAP_CONTENT so that it does not end up  
  70.                 // with a height of 0  
  71.                 oldHeight = 0;  
  72.                 lp.height = LayoutParams.WRAP_CONTENT;  
  73.             }  
  74.   
  75.             // Determine how big this child would like to be. If this or  
  76.             // previous children have given a weight, then we allow it to  
  77.             // use all available space (and we will shrink things later  
  78.             // if needed).  
  79.             measureChildBeforeLayout(  
  80.                    child, i, widthMeasureSpec, 0, heightMeasureSpec,  
  81.                    totalWeight == 0 ? mTotalLength : 0);  
  82.   
  83.             if (oldHeight != Integer.MIN_VALUE) {  
  84.                lp.height = oldHeight;  
  85.             }  
  86.   
  87.             final int childHeight = child.getMeasuredHeight();  
  88.             final int totalLength = mTotalLength;  
  89.             mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +  
  90.                    lp.bottomMargin + getNextLocationOffset(child));  
  91.   
  92.             if (useLargestChild) {  
  93.                 largestChildHeight = Math.max(childHeight, largestChildHeight);  
  94.             }  
  95.         }  
  96.   
  97.         /** 
  98.          * If applicable, compute the additional offset to the child's baseline 
  99.          * we'll need later when asked {@link #getBaseline}. 
  100.          */  
  101.         if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {  
  102.            mBaselineChildTop = mTotalLength;  
  103.         }  
  104.   
  105.         // if we are trying to use a child index for our baseline, the above  
  106.         // book keeping only works if there are no children above it with  
  107.         // weight.  fail fast to aid the developer.  
  108.         if (i < baselineChildIndex && lp.weight > 0) {  
  109.             throw new RuntimeException("A child of LinearLayout with index "  
  110.                     + "less than mBaselineAlignedChildIndex has weight > 0, which "  
  111.                     + "won't work.  Either remove the weight, or don't set "  
  112.                     + "mBaselineAlignedChildIndex.");  
  113.         }  
  114.   
  115.         boolean matchWidthLocally = false;  
  116.         if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {  
  117.             // The width of the linear layout will scale, and at least one  
  118.             // child said it wanted to match our width. Set a flag  
  119.             // indicating that we need to remeasure at least that view when  
  120.             // we know our width.  
  121.             matchWidth = true;  
  122.             matchWidthLocally = true;  
  123.         }  
  124.   
  125.         final int margin = lp.leftMargin + lp.rightMargin;  
  126.         final int measuredWidth = child.getMeasuredWidth() + margin;  
  127.         maxWidth = Math.max(maxWidth, measuredWidth);  
  128.         childState = combineMeasuredStates(childState, child.getMeasuredState());  
  129.   
  130.         allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;  
  131.         if (lp.weight > 0) {  
  132.             /* 
  133.              * Widths of weighted Views are bogus if we end up 
  134.              * remeasuring, so keep them separate. 
  135.              */  
  136.             weightedMaxWidth = Math.max(weightedMaxWidth,  
  137.                     matchWidthLocally ? margin : measuredWidth);  
  138.         } else {  
  139.             alternativeMaxWidth = Math.max(alternativeMaxWidth,  
  140.                     matchWidthLocally ? margin : measuredWidth);  
  141.         }  
  142.   
  143.         i += getChildrenSkipCount(child, i);  
  144.     }  
  145.   
  146.     if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {  
  147.         mTotalLength += mDividerHeight;  
  148.     }  
  149.   
  150.     if (useLargestChild &&  
  151.             (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {  
  152.         mTotalLength = 0;  
  153.   
  154.         for (int i = 0; i < count; ++i) {  
  155.             final View child = getVirtualChildAt(i);  
  156.   
  157.             if (child == null) {  
  158.                 mTotalLength += measureNullChild(i);  
  159.                 continue;  
  160.             }  
  161.   
  162.             if (child.getVisibility() == GONE) {  
  163.                 i += getChildrenSkipCount(child, i);  
  164.                 continue;  
  165.             }  
  166.   
  167.             final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)  
  168.                     child.getLayoutParams();  
  169.             // Account for negative margins  
  170.             final int totalLength = mTotalLength;  
  171.             mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +  
  172.                     lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));  
  173.         }  
  174.     }  
  175.   
  176.     // Add in our padding  
  177.     mTotalLength += mPaddingTop + mPaddingBottom;  
  178.   
  179.     int heightSize = mTotalLength;  
  180.   
  181.     // Check against our minimum height  
  182.     heightSize = Math.max(heightSize, getSuggestedMinimumHeight());  
  183.       
  184.     // Reconcile our calculated size with the heightMeasureSpec  
  185.     int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);  
  186.     heightSize = heightSizeAndState & MEASURED_SIZE_MASK;  
  187.       
  188.     // Either expand children with weight to take up available space or  
  189.     // shrink them if they extend beyond our current bounds. If we skipped  
  190.     // measurement on any children, we need to measure them now.  
  191.     int delta = heightSize - mTotalLength;  
  192.     if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {  
  193.         float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;  
  194.   
  195.         mTotalLength = 0;  
  196.   
  197.         for (int i = 0; i < count; ++i) {  
  198.             final View child = getVirtualChildAt(i);  
  199.               
  200.             if (child.getVisibility() == View.GONE) {  
  201.                 continue;  
  202.             }  
  203.               
  204.             LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();  
  205.               
  206.             float childExtra = lp.weight;  
  207.             if (childExtra > 0) {  
  208.                 // Child said it could absorb extra space -- give him his share  
  209.                 int share = (int) (childExtra * delta / weightSum);  
  210.                 weightSum -= childExtra;  
  211.                 delta -= share;  
  212.   
  213.                 final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,  
  214.                         mPaddingLeft + mPaddingRight +  
  215.                                 lp.leftMargin + lp.rightMargin, lp.width);  
  216.   
  217.                 // TODO: Use a field like lp.isMeasured to figure out if this  
  218.                 // child has been previously measured  
  219.                 if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) {  
  220.                     // child was measured once already above...  
  221.                     // base new measurement on stored values  
  222.                     int childHeight = child.getMeasuredHeight() + share;  
  223.                     if (childHeight < 0) {  
  224.                         childHeight = 0;  
  225.                     }  
  226.                       
  227.                     child.measure(childWidthMeasureSpec,  
  228.                             MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));  
  229.                 } else {  
  230.                     // child was skipped in the loop above.  
  231.                     // Measure for this first time here        
  232.                     child.measure(childWidthMeasureSpec,  
  233.                             MeasureSpec.makeMeasureSpec(share > 0 ? share : 0,  
  234.                                     MeasureSpec.EXACTLY));  
  235.                 }  
  236.   
  237.                 // Child may now not fit in vertical dimension.  
  238.                 childState = combineMeasuredStates(childState, child.getMeasuredState()  
  239.                         & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));  
  240.             }  
  241.   
  242.             final int margin =  lp.leftMargin + lp.rightMargin;  
  243.             final int measuredWidth = child.getMeasuredWidth() + margin;  
  244.             maxWidth = Math.max(maxWidth, measuredWidth);  
  245.   
  246.             boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&  
  247.                     lp.width == LayoutParams.MATCH_PARENT;  
  248.   
  249.             alternativeMaxWidth = Math.max(alternativeMaxWidth,  
  250.                     matchWidthLocally ? margin : measuredWidth);  
  251.   
  252.             allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;  
  253.   
  254.             final int totalLength = mTotalLength;  
  255.             mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +  
  256.                     lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));  
  257.         }  
  258.   
  259.         // Add in our padding  
  260.         mTotalLength += mPaddingTop + mPaddingBottom;  
  261.         // TODO: Should we recompute the heightSpec based on the new total length?  
  262.     } else {  
  263.         alternativeMaxWidth = Math.max(alternativeMaxWidth,  
  264.                                        weightedMaxWidth);  
  265.   
  266.   
  267.         // We have no limit, so make all weighted views as tall as the largest child.  
  268.         // Children will have already been measured once.  
  269.         if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {  
  270.             for (int i = 0; i < count; i++) {  
  271.                 final View child = getVirtualChildAt(i);  
  272.   
  273.                 if (child == null || child.getVisibility() == View.GONE) {  
  274.                     continue;  
  275.                 }  
  276.   
  277.                 final LinearLayout.LayoutParams lp =  
  278.                         (LinearLayout.LayoutParams) child.getLayoutParams();  
  279.   
  280.                 float childExtra = lp.weight;  
  281.                 if (childExtra > 0) {  
  282.                     child.measure(  
  283.                             MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),  
  284.                                     MeasureSpec.EXACTLY),  
  285.                             MeasureSpec.makeMeasureSpec(largestChildHeight,  
  286.                                     MeasureSpec.EXACTLY));  
  287.                 }  
  288.             }  
  289.         }  
  290.     }  
  291.   
  292.     if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {  
  293.         maxWidth = alternativeMaxWidth;  
  294.     }  
  295.       
  296.     maxWidth += mPaddingLeft + mPaddingRight;  
  297.   
  298.     // Check against our minimum width  
  299.     maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());  
  300.       
  301.     setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),  
  302.             heightSizeAndState);  
  303.   
  304.     if (matchWidth) {  
  305.         forceUniformWidth(count, heightMeasureSpec);  
  306.     }  
  307. }  
    /**
     * Measures the children when the orientation of this LinearLayout is set
     * to {@link #VERTICAL}.
     *
     * @param widthMeasureSpec Horizontal space requirements as imposed by the parent.
     * @param heightMeasureSpec Vertical space requirements as imposed by the parent.
     *
     * @see #getOrientation()
     * @see #setOrientation(int)
     * @see #onMeasure(int, int)
     */
    void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
        mTotalLength = 0;
        int maxWidth = 0;
        int childState = 0;
        int alternativeMaxWidth = 0;
        int weightedMaxWidth = 0;
        boolean allFillParent = true;
        float totalWeight = 0;

        final int count = getVirtualChildCount();
        
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        boolean matchWidth = false;
        boolean skippedMeasure = false;

        final int baselineChildIndex = mBaselineAlignedChildIndex;        
        final boolean useLargestChild = mUseLargestChild;

        int largestChildHeight = Integer.MIN_VALUE;

        // See how tall everyone is. Also remember max width.
        for (int i = 0; i < count; ++i) {
            final View child = getVirtualChildAt(i);

            if (child == null) {
                mTotalLength += measureNullChild(i);
                continue;
            }

            if (child.getVisibility() == View.GONE) {
               i += getChildrenSkipCount(child, i);
               continue;
            }

            if (hasDividerBeforeChildAt(i)) {
                mTotalLength += mDividerHeight;
            }

            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();

            totalWeight += lp.weight;
            
            if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {
                // Optimization: don't bother measuring children who are going to use
                // leftover space. These views will get measured again down below if
                // there is any leftover space.
                final int totalLength = mTotalLength;
                mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
                skippedMeasure = true;
            } else {
                int oldHeight = Integer.MIN_VALUE;

                if (lp.height == 0 && lp.weight > 0) {
                    // heightMode is either UNSPECIFIED or AT_MOST, and this
                    // child wanted to stretch to fill available space.
                    // Translate that to WRAP_CONTENT so that it does not end up
                    // with a height of 0
                    oldHeight = 0;
                    lp.height = LayoutParams.WRAP_CONTENT;
                }

                // Determine how big this child would like to be. If this or
                // previous children have given a weight, then we allow it to
                // use all available space (and we will shrink things later
                // if needed).
                measureChildBeforeLayout(
                       child, i, widthMeasureSpec, 0, heightMeasureSpec,
                       totalWeight == 0 ? mTotalLength : 0);

                if (oldHeight != Integer.MIN_VALUE) {
                   lp.height = oldHeight;
                }

                final int childHeight = child.getMeasuredHeight();
                final int totalLength = mTotalLength;
                mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +
                       lp.bottomMargin + getNextLocationOffset(child));

                if (useLargestChild) {
                    largestChildHeight = Math.max(childHeight, largestChildHeight);
                }
            }

            /**
             * If applicable, compute the additional offset to the child's baseline
             * we'll need later when asked {@link #getBaseline}.
             */
            if ((baselineChildIndex >= 0) && (baselineChildIndex == i + 1)) {
               mBaselineChildTop = mTotalLength;
            }

            // if we are trying to use a child index for our baseline, the above
            // book keeping only works if there are no children above it with
            // weight.  fail fast to aid the developer.
            if (i < baselineChildIndex && lp.weight > 0) {
                throw new RuntimeException("A child of LinearLayout with index "
                        + "less than mBaselineAlignedChildIndex has weight > 0, which "
                        + "won't work.  Either remove the weight, or don't set "
                        + "mBaselineAlignedChildIndex.");
            }

            boolean matchWidthLocally = false;
            if (widthMode != MeasureSpec.EXACTLY && lp.width == LayoutParams.MATCH_PARENT) {
                // The width of the linear layout will scale, and at least one
                // child said it wanted to match our width. Set a flag
                // indicating that we need to remeasure at least that view when
                // we know our width.
                matchWidth = true;
                matchWidthLocally = true;
            }

            final int margin = lp.leftMargin + lp.rightMargin;
            final int measuredWidth = child.getMeasuredWidth() + margin;
            maxWidth = Math.max(maxWidth, measuredWidth);
            childState = combineMeasuredStates(childState, child.getMeasuredState());

            allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
            if (lp.weight > 0) {
                /*
                 * Widths of weighted Views are bogus if we end up
                 * remeasuring, so keep them separate.
                 */
                weightedMaxWidth = Math.max(weightedMaxWidth,
                        matchWidthLocally ? margin : measuredWidth);
            } else {
                alternativeMaxWidth = Math.max(alternativeMaxWidth,
                        matchWidthLocally ? margin : measuredWidth);
            }

            i += getChildrenSkipCount(child, i);
        }

        if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {
            mTotalLength += mDividerHeight;
        }

        if (useLargestChild &&
                (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
            mTotalLength = 0;

            for (int i = 0; i < count; ++i) {
                final View child = getVirtualChildAt(i);

                if (child == null) {
                    mTotalLength += measureNullChild(i);
                    continue;
                }

                if (child.getVisibility() == GONE) {
                    i += getChildrenSkipCount(child, i);
                    continue;
                }

                final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
                        child.getLayoutParams();
                // Account for negative margins
                final int totalLength = mTotalLength;
                mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +
                        lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
            }
        }

        // Add in our padding
        mTotalLength += mPaddingTop + mPaddingBottom;

        int heightSize = mTotalLength;

        // Check against our minimum height
        heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
        
        // Reconcile our calculated size with the heightMeasureSpec
        int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
        heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
        
        // Either expand children with weight to take up available space or
        // shrink them if they extend beyond our current bounds. If we skipped
        // measurement on any children, we need to measure them now.
        int delta = heightSize - mTotalLength;
        if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
            float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;

            mTotalLength = 0;

            for (int i = 0; i < count; ++i) {
                final View child = getVirtualChildAt(i);
                
                if (child.getVisibility() == View.GONE) {
                    continue;
                }
                
                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
                
                float childExtra = lp.weight;
                if (childExtra > 0) {
                    // Child said it could absorb extra space -- give him his share
                    int share = (int) (childExtra * delta / weightSum);
                    weightSum -= childExtra;
                    delta -= share;

                    final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
                            mPaddingLeft + mPaddingRight +
                                    lp.leftMargin + lp.rightMargin, lp.width);

                    // TODO: Use a field like lp.isMeasured to figure out if this
                    // child has been previously measured
                    if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) {
                        // child was measured once already above...
                        // base new measurement on stored values
                        int childHeight = child.getMeasuredHeight() + share;
                        if (childHeight < 0) {
                            childHeight = 0;
                        }
                        
                        child.measure(childWidthMeasureSpec,
                                MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
                    } else {
                        // child was skipped in the loop above.
                        // Measure for this first time here      
                        child.measure(childWidthMeasureSpec,
                                MeasureSpec.makeMeasureSpec(share > 0 ? share : 0,
                                        MeasureSpec.EXACTLY));
                    }

                    // Child may now not fit in vertical dimension.
                    childState = combineMeasuredStates(childState, child.getMeasuredState()
                            & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
                }

                final int margin =  lp.leftMargin + lp.rightMargin;
                final int measuredWidth = child.getMeasuredWidth() + margin;
                maxWidth = Math.max(maxWidth, measuredWidth);

                boolean matchWidthLocally = widthMode != MeasureSpec.EXACTLY &&
                        lp.width == LayoutParams.MATCH_PARENT;

                alternativeMaxWidth = Math.max(alternativeMaxWidth,
                        matchWidthLocally ? margin : measuredWidth);

                allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;

                final int totalLength = mTotalLength;
                mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredHeight() +
                        lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
            }

            // Add in our padding
            mTotalLength += mPaddingTop + mPaddingBottom;
            // TODO: Should we recompute the heightSpec based on the new total length?
        } else {
            alternativeMaxWidth = Math.max(alternativeMaxWidth,
                                           weightedMaxWidth);


            // We have no limit, so make all weighted views as tall as the largest child.
            // Children will have already been measured once.
            if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
                for (int i = 0; i < count; i++) {
                    final View child = getVirtualChildAt(i);

                    if (child == null || child.getVisibility() == View.GONE) {
                        continue;
                    }

                    final LinearLayout.LayoutParams lp =
                            (LinearLayout.LayoutParams) child.getLayoutParams();

                    float childExtra = lp.weight;
                    if (childExtra > 0) {
                        child.measure(
                                MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),
                                        MeasureSpec.EXACTLY),
                                MeasureSpec.makeMeasureSpec(largestChildHeight,
                                        MeasureSpec.EXACTLY));
                    }
                }
            }
        }

        if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {
            maxWidth = alternativeMaxWidth;
        }
        
        maxWidth += mPaddingLeft + mPaddingRight;

        // Check against our minimum width
        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
        
        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                heightSizeAndState);

        if (matchWidth) {
            forceUniformWidth(count, heightMeasureSpec);
        }
    }

      LinearLayout首先会对所有的子View进行measure,并计算totalWeight(所有子View的weight属性之和),然后判断子View的weight属性是否为最大,如为最大则将剩余的空间分配给它。如果不使用weight属性进行布局,则不进行第二次measure。

      父视图在对子视图进行measure操作的过程中,使用变量mTotalLength保存已经measure过的child所占用的高度,该变量刚开始时是0。在for循环中调用measureChildBeforeLayout()对每一个child进行测量,该函数实际上仅仅是调用了measureChildWithMargins(),在调用该方法时,使用了两个参数。其中一个是heightMeasureSpec,该参数为LinearLayout本身的measureSpec;另一个参数就是mTotalLength,代表该LinearLayout已经被其子视图所占用的高度。 每次for循环对child测量完毕后,调用child.getMeasuredHeight()获取该子视图最终的高度,并将这个高度添加到mTotalLength中。在本步骤中,暂时避开了lp.weight>0的子视图,即暂时先不测量这些子视图,因为后面将把父视图剩余的高度按照weight值的大小平均分配给相应的子视图。源码中使用了一个局部变量totalWeight累计所有子视图的weight值。处理lp.weight>0的情况需要注意,如果变量heightMode是EXACTLY,那么,当其他子视图占满父视图的高度后,weight>0的子视图可能分配不到布局空间,从而不被显示,只有当heightMode是AT_MOST或者UNSPECIFIED时,weight>0的视图才能优先获得布局高度。

    最后我们的结论是:如果不使用weight属性,LinearLayout会在当前方向上进行一次measure的过程,如果使用weight属性,LinearLayout会避开设置过weight属性的view做第一次measure,完了再对设置过weight属性的view做第二次measure。由此可见,weight属性对性能是有影响的,而且本身有大坑,请注意避让。

三、小结

从源码中我们似乎能看出,我们先前的测试结果中RelativeLayout不如LinearLayout快的根本原因是RelativeLayout需要对其子View进行两次measure过程。而LinearLayout则只需一次measure过程,所以显然会快于RelativeLayout,但是如果LinearLayout中有weight属性,则也需要进行两次measure,但即便如此,应该仍然会比RelativeLayout的情况好一点。 RelativeLayout另一个性能问题 对比到这里就结束了嘛?显然没有!我们再看看View的Measure()方法都干了些什么?

   
  1. public final void measure(int widthMeasureSpec, int heightMeasureSpec) {  
  2.     if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||  
  3.         widthMeasureSpec != mOldWidthMeasureSpec ||  
  4.         heightMeasureSpec != mOldHeightMeasureSpec) {  
  5.                      ......  
  6.       }  
  7.        mOldWidthMeasureSpec = widthMeasureSpec;  
  8.     mOldHeightMeasureSpec = heightMeasureSpec;  
  9.   
  10.     mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |  
  11.         (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension  
  12.   }  

     View的measure方法里对绘制过程做了一个优化,如果我们或者我们的子View没有要求强制刷新,而父View给子View的传入值也没有变化(也就是说子View的位置没变化),就不会做无谓的measure。但是上面已经说了RelativeLayout要做两次measure,而在做横向的测量时,纵向的测量结果尚未完成,只好暂时使用myHeight传入子View系统,假如子View的Height不等于(设置了margin)myHeight的高度,那么measure中上面代码所做得优化将不起作用,这一过程将进一步影响RelativeLayout的绘制性能。而LinearLayout则无这方面的担忧。解决这个问题也很好办,如果可以,尽量使用padding代替margin。

结论

(1)RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View 2次onMeasure
(2)RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
(3)在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
(4)提高绘制性能的使用方式
    根据上面源码的分析,RelativeLayout将对所有的子View进行两次measure,而LinearLayout在使用weight属性进行布局时也会对子View进行两次measure,如果他们位于整个View树的顶端时并可能进行多层的嵌套时,位于底层的View将会进行大量的measure操作,大大降低程序性能。因此,应尽量将RelativeLayout和LinearLayout置于View树的底层,并减少嵌套。
    最后思考一下文章开头的疑问:较低的SDK版本新建Android项目时,默认的布局文件是采用线性布局LinearLayout,但现在自动生成的布局文件都是RelativeLayout,为什么呢?
    这是Google关于RelativeLayout的说明:

    
  1. A RelativeLayout is a very powerful utility for designing a user interface because it can eliminate nested view groups and keep your layout hierarchy flat, which improves performance. If you find yourself using several nested LinearLayout groups, you may be able to replace them with a single RelativeLayout.  
A RelativeLayout is a very powerful utility for designing a user interface because it can eliminate nested view groups and keep your layout hierarchy flat, which improves performance. If you find yourself using several nested LinearLayout groups, you may be able to replace them with a single RelativeLayout.
   Google的意思是“性能至上”, RelativeLayout 在性能上更好,因为在诸如 ListView 等控件中,使用 LinearLayout 容易产生多层嵌套的布局结构,这在性能上是不好的。而 RelativeLayout 因其原理上的灵活性,通常层级结构都比较扁平,很多使用LinearLayout 的情况都可以用一个 RelativeLayout 来替代,以降低布局的嵌套层级,优化性能。所以从这一点来看,Google比较推荐开发者使用RelativeLayout,因此就将其作为Blank Activity的默认布局了。

参考资料:
【1】《Android中RelativeLayout和LinearLayout性能分析》 http://www.jianshu.com/p/8a7d059da746 
【2】《Android RelativeLayout和LinearLayout性能分析》 http://www.tuicool.com/articles/uQ3MBnj 

线性布局和相对布局的实现原理 前言 对于中高级的工程师来说,有一定的阅读源码的经验已经必备技能之一了,尤其是 LinearLayout 和 RelativeLayout,我们先准备一下要掌握的知识点: LinearLayout 的 Weight 是如何实现的? LinearLayout 的 Weight 对于测量过程增加了哪些实现成本? LinearLayout 的 Weight 真的会导致需要测量两次吗? Relative... 阅读详情

相关推荐

Qt+OpenGL+Cesium三件套:打造高性能3D GIS界面的5个关键技巧

本文深入探讨了如何利用Qt、OpenGL与Cesium三件套打造高性能3D GIS界面的5个核心技巧。内容涵盖多线程渲染架构设计、OpenGL状态管理与批处理优化、内存与显存高效管理、Qt UI与3D场景深度集成,以及跨平台部署与性能调优实战,旨在帮助开发者解决海量3D Tiles数据渲染的性能瓶颈,实现流畅的交互体验。

t8u9v0的博客 549

Android学习笔记(六):常用布局--LinearLayout线性布局、RelativeLayout相对布局、GridLayout网格布局、ScrollView滚动视图

通过本章的学习,可以掌握三种常用的布局和一个滚动视图:LinearLayout线性布局、RelativeLayout相对布局、GridLayout网格布局、ScrollView滚动视图

CJ_study的博客 2332

DPO(Direct Preference Optimization)直接偏好优化

本文介绍了DPO(直接偏好优化)方法,该方法通过简化传统的RLHF(基于人类反馈的强化学习)流程,直接利用人类偏好数据进行模型优化。DPO的核心思想是跳过奖励模型训练和强化学习交互步骤,通过数学推导将优化目标转化为仅与策略概率分布相关的形式。推导表明最优策略与奖励模型之间存在显式关系,从而可以构建直接优化策略的损失函数。与RLHF相比,DPO简化了训练流程,提高了工程实现稳定性,同时保持了同等效果。

TeenLucifer的博客 1956

LinearLayout和RelativeLayout属性和性能详解

一、前期基础知识储备上,官方文档   由上面的官方文档,我们可以看出,两个布局方式的相同,都是继承自View.Group,是一种容器控件,LinearLayout的布局层次比较简单,方向和位置都比较容易控制,而相对布局RelativeLayout 对于其内子控件提供了更加丰富的布局层次和布局位置。二、两者在属性上的异同点共有属性: java代码中通过btn1关联次控件 android:id="@+...

Chin_Style的博客 8954

QT触摸屏开发:如何通过重写事件处理实现精准按键长按检测

本文针对QT触摸屏开发中按键长按检测不精准的常见问题,深入剖析了传统信号机制失效的原因,并提供了通过重写事件处理函数(event)的解决方案。文章详细介绍了创建自定义TouchButton类、直接处理QTouchEvent以实现可靠长按检测的完整步骤与代码示例,并分享了进阶优化与避坑指南,帮助开发者实现跨平台一致的精准交互。

weixin_29207149的博客 95

​基于stm32的智能空气加湿器设计(含源代码和Proteus仿真)

课程设计分享

LoongSTUDIO的博客 2927

LinearLayout 与RelativeLayout的区别

一、线性布局(LinearLayout) 线性布局:线性布局是我们在开发中最常见的布局方式之一,线性布局可以分为水平线性布局和垂直线性布局这两种布局方式 线性布局的属性...

我的未来鵏溡儚 1125

STM32CubeMX | 38-使用硬件SPI驱动以太网模块(W5500)

本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件SPI外设与以W5500通信,驱动以太网模块。 1. 准备工作 硬件准备 开发板 首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi): W5500以太网模块 这里我使用常见的以太网模块W5500: W5500官网 http://www.w5500.cn/ W5500中文手册 iEthernet W5500 Datasheet 软件准备 需要安装好Keil - MDK及芯片对应的包,以

Mculover666的博客(嵌入式) 7388

Android开发——LinearLayout和RelativeLayout的性能对比

转:http://blog.youkuaiyun.com/seu_calvin/article/details/53047682 0. 前言 我们都知道,新建一个Android项目SDK会为我们自动生成的avtivity_main.xml布局文件,然后它的根节点默认是RelativeLayout,在我们的理解里貌似LinearLayout的性能是要比RelativeLayout更优的,比如作为

lzc394049722的博客 574

大数据在电力行业的应用案例解析 -【电力技术】(十)电力数字化运营与大数据精准服务体系建设

电力数字化运营,是大数据在电力行业从技术场景走向业务价值的最终落点。它以数据为纽带,将用户、设备、服务、收益、风险全部纳入统一闭环,实现从 “管好电” 向 “运营好能源资产” 升级。在新型电力系统与市场化改革双重驱动下,谁能用好数据、建好闭环、做好运营,谁就能在服务、成本、效益、安全上建立长期优势。

getusushu的博客 69

keil内无法打开ccs图形编程,弹框提示:无法加载一下来源的扩展程序:C:\...清单文件缺失或不可读取,如何解决?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!

**My Coding Family** 1377

RelativeLayout和LinearLayout性能比较 相对布局和线性布局的性能比较(结论)

相对布局和线性布局的性能比较(结论) (1)RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View 2次onMeasure (2)RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加 严重。如果可...

mdbhjj_163的博客 1454

SAP FICO 科目余额查询表开发说明书(包括测试样例、程序代码仅作参考,不保证一定可以运行)

SAP FICO 科目余额查询表开发说明书(包括开发源代码、测试样例)

我好像病了的博客 1041

Android中常用的布局以及性能你了解多少?

大家都知道 在Android中常用的布局有五种: 线性布局(LinearLayout):按照垂直或者水平方向布局的一种组件。 相对布局(RelativeLayout):相对某个组件的布局方式。 帧布局(FrameLayout):组件从屏幕左上方布局组件一层一层。 表格布局(TableLayout):按照行列方式布局组件类似于表格。 绝对布局(AbsoluteLayout):按坐标来布局某

qq_37014804的博客 1747

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Android学习杂记(二)布局

android:layout_height 和 android:width 的属性值有三个:fill_parent, match_par

张小彬的专栏 710

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

ConstraintLayout,RelativeLayout和LinearLayout的性能对比

从五年前刚接触Android开发,到初入职场。不管想写什么小demo,或者做什么课程设计,拿到需求,我就开始自己的线性布局之旅了。不管多么复杂的布局,我几乎都能通过各种嵌套来实现。但是,逐渐的,我也听到身边的同事说线性布局嵌套会导致过度绘制,影响性能等等的说法。那时,我还一脸懵逼。确实,那时候,我也只是想着完成功能。 那么,为什么我想写一篇文章来对比一下这三种布局...

zhaojun的博客 2万+

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Android常用的两种基本布局——线性布局LinearLayout和相对布局RelativeLayout

目录 一、线性布局LinearLayout 使用示例 layout_height和layout_weight常用的参数 二、相对布局RelativeLayout RelativeLayout中子控件常用属性 使用示例 一、线性布局LinearLayout 线性布局的的属性设置: android:orientation 可以设置垂直方向或者水平方向的布局。 属性值垂直(verti...

chen_i 2314

08. 【Android教程】相对布局 RelativeLayout

在上一节中我们讲到了 LinearLayout,这也是大家学到的第一个布局方式。它支持将多个 View 通过线性的方式(水平或垂直)组合起来,其中最实用的就是 weight 属性,用好 weight 可以让你的线性布局更灵活美观。然而,在上一节的例子中我们发现,如果需要在多个方向上进行布局,就要嵌套多个 LinearLayout,可以想象如果我们的 UI 足够复杂,那么从工作量和性能上都将是一场噩梦。

这是一个web全栈开发的博客,取其精华去其糟粕,争取让大家一看就懂,一学就会,一用就成~ 3615

Android:xml布局详细介绍(线性布局:LinearLayout 相对布局:RelativeLayout 条件布局:ConstraintLayout)

相对布局:相对布局也是常用的布局之一,它可以设置某一个控件相对于其他控件的位置,这些位置可以包括上下左右等,因此相较于其他的布局方式而言具有很大的灵活性。1.核心属性图2.父容器定位属性示意图3.根据兄弟组件定位恩,先说下什么是兄弟组件吧,所谓的兄弟组件就是处于同一层次容器的组件,如图图中的组件1,2就是兄弟组件了,而组件3与组件1或组件2并不是兄弟组件,所以组件3不能通过 组件1或2来进行定位,比如layout_toleftof = "组件1"这样是会报错的!切记!

2401_87555613的博客 1798

android线性布局两种形式,Android常用的两种基本布局——线性布局LinearLayout和相对布局RelativeLayout...

一、线性布局LinearLayout线性布局的的属性设置:android:orientation 可以设置垂直方向或者水平方向的布局。属性值垂直(vertical)和水平(horizontal),默认水平方向。android:gravity 内部控件对齐方式,常用属性值有center、center_vertical、center_horizontal、top、bottom、left、right等。...

weixin_39650745的博客 1527

【达内课程】布局控件之 LinearLayout 和 RelativeLayout

达内课程-布局控件之相对布局和线性布局

Errol's Blog 463

深入解析 Android 常用布局:LinearLayout、RelativeLayout 与 ConstraintLayout(含面试题)

在 Android 开发中,布局(Layout)是构建用户界面的基础,它决定了 View 的排列方式和位置关系。最常用的三大布局分别是(线性布局)、(相对布局)和(约束布局)。本文将从布局特性、使用场景、实战案例到性能对比全面解析这三种布局,并整理高频面试题,帮助开发者在实际开发中选择合适的布局方案。

2501_93564530的博客 1550

Android 线性布局、网格布局、相对布局 完全详解

布局类型核心排列规则适用场景线性布局按「水平 / 垂直」单一方向排列简单行 / 列布局(如登录按钮栏、列表项)网格布局按「行 + 列」二维网格排列规则网格界面(如计算器按钮、九宫格)相对布局按「相对位置」(相对于父 / 子)排列复杂自由布局(如首页、个性化界面)线性布局:单一方向排列,核心是(方向)和(权重),简单布局首选;网格布局:二维网格排列,核心是(行列数)和(跨行列),规则网格首选;相对布局:相对位置排列,核心是「相对于父布局 / 其他控件对齐」,复杂布局首选;通用规则。

yyxiangqianc的博客 812

RelativeLayout和LinearLayout性能比较

相对布局和线性布局的性能比较 RelativeLayout和LinearLayout是Android中常用的布局,两者的使用会极大的影响程序生成每一帧的性能,因此,正确的使用它们是提升程序性能的重要工作 (1)RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View 2次onMeasure (2)RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更

AI吃大瓜的博客 1万+
上一篇: Android webview的解析
下一篇: Android UI性能优化实战 识别绘制中的性能问题
snow_zhang_123
博客等级 码龄11年 7粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值