FrameLayout的onMeasure方法

     /**
     * {@inheritDoc}
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int count = getChildCount();
        final boolean measureMatchParentChildren =
                MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
                MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
        //当FrameLayout的宽和高,只有同时设置为match_parent或者指定的size,那么这个

        //measureMatchParentChlidren = false,否则为true。下面会用到这个变量
        
        mMatchParentChildren.clear();
        int maxHeight = 0;     
        int maxWidth = 0;
        int childState = 0;    //宽高的期望类型

        for (int i = 0; i < count; i++) {    //一次遍历每一个不为GONE的子view
    
            final View child = getChildAt(i);    
            if (mMeasureAllChildren || child.getVisibility() != GONE) {
                //去掉FrameLayout的左右padding,子view的左右margin,这时候,再去

                //计算子view的期望的值
                
                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                
                
                /*maxWidth找到子View中最大的宽,高同理,为什么要找到他,因为在这里,FrameLayout是wrap
                -content.他的宽高肯定受子view的影响*/
                
                maxWidth = Math.max(maxWidth,
                        child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
                maxHeight = Math.max(maxHeight,
                        child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
                childState = combineMeasuredStates(childState, child.getMeasuredState());
               
                /*下面的判断,只有上面的FragLayout的width和height都设置为match_parent 才不会执行
                此处的mMatchParentChlidren的list里存的是设置为match_parent的子view。
                结合上面两句话的意思,当FrameLayout设置为wrap_content,这时候要把所有宽高设置为
                match_parent的子View都记录下来,记录下来干什么呢?
                这时候FrameLayout的宽高同时受子View的影响*/
                   
                 if (measureMatchParentChildren) {
                    if (lp.width == LayoutParams.MATCH_PARENT ||
                            lp.height == LayoutParams.MATCH_PARENT) {
                        mMatchParentChildren.add(child);
                    }
                }
            }
        }
        
        // Account for padding too
        maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
        maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
        
        // Check against our minimum height and width
        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
        // Check against our foreground‘s minimum height and width
        final Drawable drawable = getForeground();
        if (drawable != null) {
            maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
            maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
        }

        //设置测量过的宽高
        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                resolveSizeAndState(maxHeight, heightMeasureSpec,
                        childState << MEASURED_HEIGHT_STATE_SHIFT));
        count = mMatchParentChildren.size();//这个大小就是子view中设定为match_parent的个数

        if (count > 1) {
            for (int i = 0; i < count; i++) {
                //这里看上去重新计算了一遍

                final View child = mMatchParentChildren.get(i);
                final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
                int childWidthMeasureSpec;
                int childHeightMeasureSpec;
                /*如果子view的宽是match_parent,则宽度期望值是总宽度-padding-margin
                 如果子view的宽是指定的比如100dp,则宽度期望值是padding+margin+width
                 这个很容易理解,下面的高同理*/
                if (lp.width == LayoutParams.MATCH_PARENT) {
                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() -
                            getPaddingLeftWithForeground() - getPaddingRightWithForeground() -
                            lp.leftMargin - lp.rightMargin,
                            MeasureSpec.EXACTLY);
                } else {
                    childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
                            getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
                            lp.leftMargin + lp.rightMargin,
                            lp.width);
                }
                
                if (lp.height == LayoutParams.MATCH_PARENT) {
                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() -
                            getPaddingTopWithForeground() - getPaddingBottomWithForeground() -
                            lp.topMargin - lp.bottomMargin,
                            MeasureSpec.EXACTLY);
                } else {
                    childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
                            getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
                            lp.topMargin + lp.bottomMargin,
                            lp.height);
                }
                //把这部分子view重新计算大小

                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            }
        }
    }
时间: 2024-10-14 01:26:57

FrameLayout的onMeasure方法的相关文章

Android自定义控件系列七:详解onMeasure()方法中如何测量一个控件尺寸(一)

转载请注明出处:http://blog.csdn.net/cyp331203/article/details/45027641 自定义view/viewgroup要重写的几个方法:onMeasure(),onLayout(),onDraw().(不熟悉的话可以查看专栏的前几篇文章:Android自定义控件系列二:自定义开关按钮(一)). 今天的任务就是详细研究一下protected void onMeasure(int widthMeasureSpec, int heightMeasureSpe

Android--MeasureSpec类和onMeasure()方法

onMeasure(测量)介绍及使用详解 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量——onMeasure():决定View的大小 2.布局——onLayout():  决定View在ViewGroup中的位置 3.绘制——onDraw():    如何绘制这个View. 而第3步的onDraw系统已经封装的很好了,基本不用我们来操心,只需要专注到 1,2两个步骤就中好了. 一般来说,自定义控件都会去重写View的onMeasure()方法,因为该方法指定该控件在屏幕上的大

Android中View的绘制过程 onMeasure方法简述

Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点. 绘制过程从布局的根节点开始,从根节点开始测量和绘制整个layout tree. 每一个ViewGroup 负责要求它的每一个孩子被绘制,每一个View负责绘制自己. 因为整个树是按顺序遍历的,所以父节点会先被绘制,而兄弟节点会按照它们在树中出现的顺序被绘制. 绘制是一个两遍(two pass)的过程:一个mea

【转】Android中View的绘制过程 onMeasure方法简述 附有自定义View例子

Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点. 绘制过程从布局的根节点开始,从根节点开始测量和绘制整个layout tree. 每一个ViewGroup 负责要求它的每一个孩子被绘制,每一个View负责绘制自己. 因为整个树是按顺序遍历的,所以父节点会先被绘制,而兄弟节点会按照它们在树中出现的顺序被绘制. 绘制是一个两遍(two pass)的过程:一个mea

Android之View.onMeasure方法

View在屏幕上显示出来要先经过measure(计算)和layout(布局). 1.什么时候调用onMeasure方法? 当控件的父元素正要放置该控件时调用.父元素会问子控件一个问题,“你想要用多大地方啊?”,然后传入两个参数——widthMeasureSpec和heightMeasureSpec. 这两个参数指明控件可获得的空间以及关于这个空间描述的元数据. 更好的方法是你传递View的高度和宽度到setMeasuredDimension方法里,这样可以直接告诉父控件,需要多大地方放置子控件.

Android View.onMeasure方法的理解

View在屏幕上显示出来要先经过measure(计算)和layout(布局).1.什么时候调用onMeasure方法? 当控件的父元素正要放置该控件时调用.父元素会问子控件一个问题,“你想要用多大地方啊?”,然后传入两个参数——widthMeasureSpec和heightMeasureSpec.这两个参数指明控件可获得的空间以及关于这个空间描述的元数据.更好的方法是你传递View的高度和宽度到setMeasuredDimension方法里,这样可以直接告诉父控件,需要多大地方放置子控件. 接下

[转]Android View.onMeasure方法的理解

转自:http://blog.sina.com.cn/s/blog_61fbf8d10100zzoy.html Android View.onMeasure方法的理解 View在屏幕上显示出来要先经过measure(计算)和layout(布局).1.什么时候调用onMeasure方法? 当控件的父元素正要放置该控件时调用.父元素会问子控件一个问题,“你想要用多大地方啊?”,然后传入两个参数——widthMeasureSpec和heightMeasureSpec.这两个参数指明控件可获得的空间以及

Android中View的绘制过程 onMeasure方法简述 附有自定义View例子

Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点. 绘制过程从布局的根节点开始,从根节点开始测量和绘制整个layout tree. 每一个ViewGroup 负责要求它的每一个孩子被绘制,每一个View负责绘制自己. 因为整个树是按顺序遍历的,所以父节点会先被绘制,而兄弟节点会按照它们在树中出现的顺序被绘制. 绘制是一个两遍(two pass)的过程:一个mea

Android onMeasure 方法的测量规范MeasureSpec

一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求.一个MeasureSpec由大小和模式组成.它有三种模式:UNSPECIFIED(未指定),父元素不对子元素施加任何束缚,子元素可以得到任意想要的大小:EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小:AT_MOST(至多),子元素至多达到指定大小的值. 它常用的三个函数: 1.static int getMode(int measu