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);//测量子Viewfinal 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); } }}
- FramLayout源码分析
- Android初试--Framlayout(帧布局)
- 自定义各种角度的Framlayout
- 左边ListView+右边framlayout占位
- 2015/8/19/FramLayout/TableLayout/AbsoluteLayout
- 【Gridlayout网格布局,Framlayout帧布局】
- 侧滑菜单+framlayout占位+RadioGroup
- 自定义控件----继承framLayout --textview与checkBox
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析
- 源码分析:SparseArray分析
- 源码- Spark Broadcast源码分析
- 数据库阿里连接池 druid配置详解
- 解决360等等浏览器兼容模式解析不兼容代码
- jxl.write.biff.RowsExceededException: The maximum number of rows permitted on a worksheet been excee
- python漫谈
- 如何让你的搜索框设计“一鸣惊人”
- FramLayout源码分析
- Android中onSaveInstanceState()数据的保存
- 【javascript】操作cookie
- testng测试报告相关pom文件
- Drawable学习之----ShapeDrawable
- math.h中的常用函数
- idea上mybatis遇到的mapper扫描问题
- spring boot 所有的Controller异常捕获
- 交叉验证