FrameLayout 测量过程(代码流水线)

来源:互联网 发布:海子为什么卧轨知乎 编辑:程序博客网 时间:2024/05/16 08:28
   /**     * {@inheritDoc}     * 如果,子 view如果设置属性是 match_parent,     * 如果,measureMatchParentChildren是true (其实就是framlayout模式是非精准模式)     * 那么这种子view是被测量了两次     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int count = getChildCount();        //当FrameLayout的宽和高 只有同时设置为 match_parent        //当FrameLayout的宽和高 指定的size        ///measureMatchParentChlidren = false,否则为true。        //MeasureSpec.EXACTLY时,就表示当前视图的大小等于参数measureSpec中所指定的值。        //当FrameLayout 非精准模式,这时候要把所有宽高设置为 //match_parent的子View都记录下来        // 这时候FrameLayout的宽高同时受子View的影响        final boolean measureMatchParentChildren = MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY || MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;        mMatchParentChildren.clear();        int maxHeight = 0;        int maxWidth = 0;        int childState = 0;//宽高的期望类型        //测量孩子同时,计算出一个最大宽高        for (int i = 0; i < count; i++) {            final View child = getChildAt(i);            if (mMeasureAllChildren || child.getVisibility() != GONE) { //一次遍历每一个不为GONE的子view                //第一次测量孩子                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);                final LayoutParams lp = (LayoutParams) child.getLayoutParams();                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());                //的mMatchParentChlidren的list里存的是设置为match_parent的子view。                if (measureMatchParentChildren) {                    if (lp.width == LayoutParams.MATCH_PARENT || lp.height == LayoutParams.MATCH_PARENT) {                        mMatchParentChildren.add(child);                    }                }            }        }        // Account for padding too        //加上父亲的padidng        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));        //上面的测量,得到了framlayout的宽,高,下面,需要根据宽高,重新测量子view - 主要是 match_parent 属性的孩子        //子view中设定为match_parent的个数        //重新测量        count = mMatchParentChildren.size();        if (count > 1) {            for (int i = 0; i < count; i++) {                final View child = mMatchParentChildren.get(i);                final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();                final int childWidthMeasureSpec;                //将属性为match_parent的再测量一遍                if (lp.width == LayoutParams.MATCH_PARENT) {//子view的宽是match_parent,则宽度期望值是总宽度-padding-margin                    final int width = Math.max(0, getMeasuredWidth()                            - getPaddingLeftWithForeground() - getPaddingRightWithForeground()                            - lp.leftMargin - lp.rightMargin);                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(                            width, MeasureSpec.EXACTLY);                } else {                    childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,                            getPaddingLeftWithForeground() + getPaddingRightWithForeground() +                                    lp.leftMargin + lp.rightMargin,                            lp.width);                }                //将属性为match_parent的再测量一遍                final int childHeightMeasureSpec;                if (lp.height == LayoutParams.MATCH_PARENT) {                    final int height = Math.max(0, getMeasuredHeight()                            - getPaddingTopWithForeground() - getPaddingBottomWithForeground()                            - lp.topMargin - lp.bottomMargin);                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(                            height, MeasureSpec.EXACTLY);                } else {                    childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,                            getPaddingTopWithForeground() + getPaddingBottomWithForeground() +                                    lp.topMargin + lp.bottomMargin,                            lp.height);                }                //子view的宽是match_parent,则宽度期望值是总宽度-padding-margin                // //把这部分子view重新计算大小                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);            }        }    }
    protected void measureChildWithMargins(View child,                                           int parentWidthMeasureSpec, int widthUsed,                                           int parentHeightMeasureSpec, int heightUsed) {        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();        //根据parentWidthMeasureSpec,ViewGroup剩余宽度,child的宽度重新计算child的widthMeasureSpec        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin                        + widthUsed, lp.width);        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin                        + heightUsed, lp.height);        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);    }
    /**     * @param spec           The requirements for this view     *                       parentHeightMeasureSpec     * @param padding        The padding of this view for the current dimension and     *                       margins, if applicable     *                       父亲已经用的 + 父亲的pading + 父亲的margin     * @param childDimension How big the child wants to be in the current     *                       dimension     * @return a MeasureSpec integer for the child     * 孩子的布局参数     */    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {        //得到父亲的测量模式和大小        int specMode = MeasureSpec.getMode(spec);        int specSize = MeasureSpec.getSize(spec);        //父亲大小 - 父亲的冗余        //当前父View还剩的空间大小        int size = Math.max(0, specSize - padding);        int resultSize = 0;        int resultMode = 0;        switch (specMode) {            // Parent has imposed an exact size on us            case MeasureSpec.EXACTLY:// 父View强制设置了一个大小给子View                if (childDimension >= 0) {//大小就是 孩子参数的大小                    resultSize = childDimension;                    resultMode = MeasureSpec.EXACTLY;                } else if (childDimension == LayoutParams.MATCH_PARENT) {//大小就是 父亲剩余空间的大小                    // Child wants to be our size. So be it.                    resultSize = size;                    resultMode = MeasureSpec.EXACTLY;                } else if (childDimension == LayoutParams.WRAP_CONTENT) {//大小设置为父亲剩余空间大小,意味着让子View去处理,子View最大的大小不能超过父View                    // Child wants to determine its own size. It can't be                    // bigger than us.                    resultSize = size;                    resultMode = MeasureSpec.AT_MOST;                }                break;            // Parent has imposed a maximum size on us            case MeasureSpec.AT_MOST:// 父View给子View一个限定的大小,子View不能超过这个大小                if (childDimension >= 0) {// 子View的size设置成XML中配置的大小                    // Child wants a specific size... so be it                    resultSize = childDimension;                    resultMode = MeasureSpec.EXACTLY;                } else if (childDimension == LayoutParams.MATCH_PARENT) {// 子View的大小为父View的size 意味着让子View去处理,子View最大的大小不能超过父View                    // Child wants to be our size, but our size is not fixed.                    // Constrain child to not be bigger than us.                    resultSize = size;                    resultMode = MeasureSpec.AT_MOST;                } else if (childDimension == LayoutParams.WRAP_CONTENT) {//同上                    // Child wants to determine its own size. It can't be                    // bigger than us.                    resultSize = size;                    resultMode = MeasureSpec.AT_MOST;                }                break;            // Parent asked to see how big we want to be            case MeasureSpec.UNSPECIFIED:// 意味着子View要多大都可以                if (childDimension >= 0) {//子View的size设置成XML中配置的大小                    // Child wants a specific size... let him have it                    resultSize = childDimension;                    resultMode = MeasureSpec.EXACTLY;//意味着,我可以给让你想显示多大就显示多大,但是在XML中或者addView的时候, 写死了childDimension,那么它的大小就这么大吧                } else if (childDimension == LayoutParams.MATCH_PARENT) {//意味着大小让它自己决定到底要多大,随便多大都可以                    // Child wants to be our size... find out how big it should                    // be                    resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;                    resultMode = MeasureSpec.UNSPECIFIED;                } else if (childDimension == LayoutParams.WRAP_CONTENT) {// 意味着大小让它自己决定到底要多大,随便多大都可以                    // Child wants to determine its own size.... find out how                    // big it should be                    resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;                    resultMode = MeasureSpec.UNSPECIFIED;                }                break;        }        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);    }
原创粉丝点击