博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
View的Layout过程源码分析
阅读量:6095 次
发布时间:2019-06-20

本文共 5703 字,大约阅读时间需要 19 分钟。

/**	 * 文档描述:	 * View的Layout过程源码分析	 * 	 * 原创作者:	 * 谷哥的小弟 http://blog.csdn.net/lfdfhl	 * 	 * 分析笔记:	 * View在经历过第一阶段的measure之后,进入到第二阶段layout.	 * 该阶段的目的是	 * (1)设置View自身的大小和位置.	 * (2)设置View的子View大小和位置.	 *      */    @SuppressWarnings({"unchecked"})    public void layout(int l, int t, int r, int b) {        int oldL = mLeft;        int oldT = mTop;        int oldB = mBottom;        int oldR = mRight;        /**         * 第一步:         * 利用setFrame()判断View的尺寸是否发生了变化.         * setFrame()的分析请参见下面的源码.         *          * 这一步就体现layout()的一个重要作用:         * 设置View自身的大小和位置         */        boolean changed = setFrame(l, t, r, b);        /**         * 第二步:         * View的尺寸发生了变化或者需要重新布局,进入该if代码段         */        if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {            if (ViewDebug.TRACE_HIERARCHY) {                ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_LAYOUT);            }            /**             * 第三步:             * 调用View的onLayou()方法.             * 这是一个非常重要的地方.             *              * 查看源码可以发现:             * View和ViewGroup中默认的onLayout方法都是空方法.             *              * 一般而言:             * 继承自View的子类不用覆写该layout(),重点应该关注onDraw().             * 继承自ViewGroup的子类不用覆写该layout(),重点应该关注onLayout()             * 且在onLayout方法中依次循环子View,并调用子View的layout方法!!!             *              * 举个例子:             * 在ViewGroupSubClass的onLayout()方法中常见如下代码:             * int childCount = getChildCount();             * for (int i = 0; i < childCount; i++) {             *      View childView = getChildAt(i);             *      childView.layout(left, top, right, bottom);              *  }             *               * 所以如果继承自ViewGroup在布局阶段应该重点关注onLayout方法中!!             *              * 这一步就体现layout()的另外一个重要作用:             * 设置View的子View大小和位置.             *              */            onLayout(changed, l, t, r, b);                        mPrivateFlags &= ~LAYOUT_REQUIRED;            /**             * 第四步:             * 调用所有OnLayoutChangeListener接口的实现,通知View大小和位置发生了改变 .             * 比如某个子view.addOnLayoutChangeListener(listener).这个listener就保存             * 在了mOnLayoutChangeListeners中.             * 这个listener在开发中还是挺有用的,值得关注             */            if (mOnLayoutChangeListeners != null) {                ArrayList
listenersCopy = (ArrayList
) mOnLayoutChangeListeners.clone(); int numListeners = listenersCopy.size(); for (int i = 0; i < numListeners; ++i) { listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); } } } mPrivateFlags &= ~FORCE_LAYOUT; } /** * setFrame()方法源码分析 * 该方法主要作用: * Assign a size and position to this view. * 为View指定大小和位置. * * 在View中表示View的大小和位置常常用到四个变量: * int left, int top, int right, int bottom * 这四个变量可以分别用以下方法获得: * getLeft(),getTop(),getRight(),getBottom() * * 但是请注意: * left 表示该View自身的左边距离parent的左边的距离 * right 表示该View自身的右边距离parent的左边的距离 * top 表示该View自身的上边距离parent的上边的距离 * bottom 表示该View自身的下边距离parent的上边的距离 * * 只要知道了这四个值也就自然确定了View的大小和坐标 * 其中宽高为: * int width = right - left; * int height = bottom - top; * 其中坐标为: * 左上角为(left,top),右下角为(right,bottom) * * * 注意该方法的返回值: * return true if the new size and position are different than the previous ones * 如果该View的尺寸发生了变化则返回true,否则返回false. * */ protected boolean setFrame(int left, int top, int right, int bottom) { boolean changed = false; if (DBG) { Log.d("View", this + " View.setFrame(" + left + "," + top + "," + right + "," + bottom + ")"); } /** * 将新旧left,right,top,bottom进行比较,若任意一对值不相等则将changed设置为true */ if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { changed = true; int drawn = mPrivateFlags & PFLAG_DRAWN; /** * 第一步: * 计算View原先的宽和高 */ int oldWidth = mRight - mLeft; int oldHeight = mBottom - mTop; /** * 第二步: * 计算View现在的宽和高 */ int newWidth = right - left; int newHeight = bottom - top; /** * 第三步: * 比较View的新旧尺寸. * 如果尺寸发生了变化则设置sizeChanged为true. * 该值稍后会用到 */ boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); /** * 第四步: * 刷新 */ invalidate(sizeChanged); /** * 第五步: * 将新得到的left,top,right,bottom保存到View的成员变量中 */ mLeft = left; mTop = top; mRight = right; mBottom = bottom; mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); mPrivateFlags |= PFLAG_HAS_BOUNDS; /** * 第六步: * 如果View的尺寸发生了变化则执行sizeChange() */ if (sizeChanged) { sizeChange(newWidth, newHeight, oldWidth, oldHeight); } if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { mPrivateFlags |= PFLAG_DRAWN; invalidate(sizeChanged); invalidateParentCaches(); } mPrivateFlags |= drawn; mBackgroundSizeChanged = true; if (mForegroundInfo != null) { mForegroundInfo.mBoundsChanged = true; } notifySubtreeAccessibilityStateChangedIfNeeded(); } return changed; }
你可能感兴趣的文章
hdu 5115(2014北京—dp)
查看>>
数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)...
查看>>
PHP读取日志里数据方法理解
查看>>
第五十七篇、AVAssetReader和AVAssetWrite 对视频进行编码
查看>>
Vivado增量式编译
查看>>
一个很好的幻灯片效果的jquery插件--kinMaxShow
查看>>
微信支付签名配置正确,但返回-1,调不出支付界面(有的手机能调起,有的不能)...
查看>>
第二周例行报告
查看>>
Spring学习(16)--- 基于Java类的配置Bean 之 基于泛型的自动装配(spring4新增)...
查看>>
实验八 sqlite数据库操作
查看>>
四种简单的排序算法(转)
查看>>
Quartz2D之着色器使用初步
查看>>
多线程条件
查看>>
Git [remote rejected] xxxx->xxxx <no such ref>修复了推送分支的错误
查看>>
Porter/Duff,图片加遮罩setColorFilter
查看>>
黄聪:VMware安装Ubuntu10.10【图解】转
查看>>
Centos 6.x 升级openssh版本
查看>>
公式推♂倒题
查看>>
vue实现点击展开,点击收起
查看>>
如何使frame能居中显示
查看>>