FramLayout源码分析

来源:互联网 发布:网络外卖订餐系统 编辑:程序博客网 时间:2024/05/22 08:19

5.4.2         绘制分析

FrameLayout继承自ViewGroup,属于view控件,因此也遵从view的绘制逻辑。

 

根据我们对view的理解,其绘制大体也是按measure—layout—draw的流程处理的。

 

 

5.4.2.1                            Measure过程

重载onMeasure,功能分3大部分:

1.遍历子view,完成每个子view的measure;

2.找到子view的最大尺寸,设置给FrameLayout,因为FrameLayout的说明里提到子view的最大尺寸就是FrameLayout的尺寸;

3.如果FrameLayout不是确定大小的模式,子view又是MATCH_PARENT属性的,则要单独为这些子view重新计算尺寸,重新measure。

 分析:一开始不知道Framelayout的大小,只能根据子View的确定FrameLayout的大小,FrameLayout大小确认后,就可以确认match_parent的View的大小;

从性能分析的角度看,单独重新measure MATCH_PARENT属性的view是耗时的,这个影响有多大,需要进行实验验证。如果对性能有一定影响,那么我们在设置FrameLayout属性和其子viewMATCH_PARENT属性时就要考虑是注重于性能,还是注重于布局的兼容性。

 

5.4.2.2                            Layout过程

这里重载了onLayout()方法,

其layout过程就是遍历所有子view的layout方法。

 

其执行流程是FrameLayout. onLayout--viewGroup.layout

--view.layout--FrameLayout的成员view.onLayout--…,这样就遍历完了FrameLayout节点下的整个view树。

 

在FrameLayout. onLayout里遍历每个成员view的时候,还根据gravity为成员view重新计算了坐标值。

 

从性能优化方面考虑,因为在代码里面gravity有默认值,所以FrameLayout的成员view是否设置gravity属性,并不影响其处理速度,同时,在onLayout里对gravity的处理并不是一个耗时流程。

 

 

5.4.2.3                            Draw过程

重载了draw方法,实现两个功能,第一是使用了父类的draw方法,绘制控件本身;第二是绘制Foreground,对于Foreground需要的时候再单独分析。

/** * {@inheritDoc} */@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    int count = getChildCount();    // FrameLayout的宽或者高有一个不是精确模式的,即Framlayout的大小是不确定的    final boolean measureMatchParentChildren =            MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||            MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;    mMatchParentChildren.clear();    int maxHeight = 0;    int maxWidth = 0;    int childState = 0;    //遍历子view,完成每个子view的measure;    for (int i = 0; i < count; i++) {        final View child = getChildAt(i);        if (mMeasureAllChildren || child.getVisibility() != GONE) {            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);//测量子View
            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());//???? if (measureMatchParentChildren) { if (lp.width == LayoutParams.MATCH_PARENT || lp.height == LayoutParams.MATCH_PARENT) { mMatchParentChildren.add(child);//把子View中宽高是Match_parent的都放入list中 } } } } // 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()); } //设置FrameLayout的测量值
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT));
//FrameLayout大小不确定时,子View的属性为match_parent时,需要重新计算子View的宽高

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(); int childWidthMeasureSpec; int childHeightMeasureSpec; 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); } child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } }}
/** * {@inheritDoc} */@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {    layoutChildren(left, top, right, bottom, false /* no force left gravity */);}void layoutChildren(int left, int top, int right, int bottom,                              boolean forceLeftGravity) {    final int count = getChildCount();    final int parentLeft = getPaddingLeftWithForeground();    final int parentRight = right - left - getPaddingRightWithForeground();    final int parentTop = getPaddingTopWithForeground();    final int parentBottom = bottom - top - getPaddingBottomWithForeground();    mForegroundBoundsChanged = true;        for (int i = 0; i < count; i++) {        final View child = getChildAt(i);        if (child.getVisibility() != GONE) {            final LayoutParams lp = (LayoutParams) child.getLayoutParams();            final int width = child.getMeasuredWidth();            final int height = child.getMeasuredHeight();            int childLeft;            int childTop;            int gravity = lp.gravity;            if (gravity == -1) {                gravity = DEFAULT_CHILD_GRAVITY;            }            final int layoutDirection = getLayoutDirection();            final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);            final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;            switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {                case Gravity.CENTER_HORIZONTAL:                    childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +                    lp.leftMargin - lp.rightMargin;                    break;                case Gravity.RIGHT:                    if (!forceLeftGravity) {                        childLeft = parentRight - width - lp.rightMargin;                        break;                    }                case Gravity.LEFT:                default:                    childLeft = parentLeft + lp.leftMargin;            }            switch (verticalGravity) {                case Gravity.TOP:                    childTop = parentTop + lp.topMargin;                    break;                case Gravity.CENTER_VERTICAL:                    childTop = parentTop + (parentBottom - parentTop - height) / 2 +                    lp.topMargin - lp.bottomMargin;                    break;                case Gravity.BOTTOM:                    childTop = parentBottom - height - lp.bottomMargin;                    break;                default:                    childTop = parentTop + lp.topMargin;            }            child.layout(childLeft, childTop, childLeft + width, childTop + height);        }    }}


原创粉丝点击