View工作原理(四)view的layout过程

转载请说明出处:http://blog.csdn.net/ff20081528/article/details/17784911刚过完自己的本命年,新的一年希望自己有个新的开始,祝自己在新的一年里一帆风顺,同时也祝广大的朋友们新年新气象,收获多多!
一、android中view的layout过程总概
	Layout过程其实就是父视图按照子视图的大小及布局参数将子视图放在窗口的合适的位置上。
	视图的布局过程是从ViewRoot对象调调用根视图的layout()方法开始,接着layout()方法调用根视图的onLayout()方法,onLayout()方法会对所包含的子视图逐一执行layout操作,如果子视图是ViewGroup子类对象,则继续调用子视图的layout(),重复这一过程。如果子视图是View子类对象,则在子视图重载的onLayout()内部只需要将自己布局到视图中,不需要对子视图进行layout操作,这样一次layout过程结束。过程如下图:

 
转载请说明出处:http://blog.csdn.net/ff20081528/article/details/17784911
二、layout详细过程
View中的layout()方法源码(ViewGroup类继承了View类,layout过程先从ViewGroup子类开始):

[java] view plaincopy

  1. /**
  2. * Assign a size and position to a view and all of its
  3. * descendants
  4. *
  5. * <p>This is the second phase of the layout mechanism.
  6. * (The first is measuring). In this phase, each parent calls
  7. * layout on all of its children to position them.
  8. * This is typically done using the child measurements
  9. * that were stored in the measure pass().
  10. *
  11. * Derived classes with children should override
  12. * onLayout. In that method, they should
  13. * call layout on each of their their children.
  14. *
  15. * @param l Left position, relative to parent
  16. * @param t Top position, relative to parent
  17. * @param r Right position, relative to parent
  18. * @param b Bottom position, relative to parent
  19. */
  20. public final void layout(int l, int t, int r, int b) {
  21. boolean changed = setFrame(l, t, r, b);
  22. if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
  23. if (ViewDebug.TRACE_HIERARCHY) {
  24. ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_LAYOUT);
  25. }
  26. onLayout(changed, l, t, r, b);
  27. mPrivateFlags &= ~LAYOUT_REQUIRED;
  28. }
  29. mPrivateFlags &= ~FORCE_LAYOUT;
  30. }
 

a) 首先我们看这个方法的定义,用了关键字final,说明此方法是不可被重写的,这样也就保证了View的layout过程是不变的。四个参数看注释,左、上、右、下分别相距父视图的距离。

b) 调用setFrame(l,t,r,b)将位置保存起来,这些参数将保存到View内部变量 (mLeft、mTop、mRight、mBottom)中。保存完变量前,会先对比这些参数是否和原来的相同,如果相同,则什么都不做,如果不同则进行重新赋值,并在赋值前给mPrivateFlags中添加DRAWN标识,同时调用invalidate()通知View系统原来占用的位置需要重绘。

c) 调用onLayout(),View中定义的onLayout()方法默认什么都不做,View系统提供onLayout()方法的目的是为了使系统包含的子视图的父视图能够在onLayout()方法对子视图进行位置分配,正因为如此,如果是父视图,则必须重写onLayout(),也正因为如此ViewGroup类才会把onLayout重载改成了abstract类型。

d)清除mPrivateFlags中的LAYOUT_REQUIRED标识,因为layout操作已经完成。

上面提到的setFrame方法源码如下:

[java] view plaincopy

  1. protected boolean setFrame(int left, int top, int right, int bottom) {
  2. boolean changed = false;
  3. if (DBG) {
  4. Log.d("View", this + " View.setFrame(" + left + "," + top + ","
  5. + right + "," + bottom + ")");
  6. }
  7. if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
  8. changed = true;
  9. // Remember our drawn bit
  10. int drawn = mPrivateFlags & DRAWN;
  11. // Invalidate our old position
  12. invalidate();
  13. int oldWidth = mRight - mLeft;
  14. int oldHeight = mBottom - mTop;
  15. mLeft = left;
  16. mTop = top;
  17. mRight = right;
  18. mBottom = bottom;
  19. mPrivateFlags |= HAS_BOUNDS;
  20. int newWidth = right - left;
  21. int newHeight = bottom - top;
  22. if (newWidth != oldWidth || newHeight != oldHeight) {
  23. onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
  24. }
  25. if ((mViewFlags & VISIBILITY_MASK) == VISIBLE) {
  26. // If we are visible, force the DRAWN bit to on so that
  27. // this invalidate will go through (at least to our parent).
  28. // This is because someone may have invalidated this view
  29. // before this call to setFrame came in, therby clearing
  30. // the DRAWN bit.
  31. mPrivateFlags |= DRAWN;
  32. invalidate();
  33. }
  34. // Reset drawn bit to original value (invalidate turns it off)
  35. mPrivateFlags |= drawn;
  36. mBackgroundSizeChanged = true;
  37. }
  38. return changed;
  39. }
 View中的onLayout()方法如下:

[java] view plaincopy

  1. protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
  2. }

而ViewGroup中的onLayout()方法如下:

[java] view plaincopy

  1. @Override
  2. protected abstract void onLayout(boolean changed,
  3. int l, int t, int r, int b);

转载请说明出处:http://blog.csdn.net/ff20081528/article/details/17784911

因为ViewGroup中的onLayout()方法是一个抽象方法,所以下面我们用他的子类LinearLayout中的onLayout()方法来分析。源码如下:

onlayout()方法:

[java] view plaincopy

  1. @Override
  2. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  3. if (mOrientation == VERTICAL) {
  4. layoutVertical();
  5. } else {
  6. layoutHorizontal();
  7. }
  8. }

layoutVertical()方法源码:

[java] view plaincopy

  1. void layoutVertical() {
  2. final int paddingLeft = mPaddingLeft;
  3. int childTop = mPaddingTop;
  4. int childLeft;
  5. // Where right end of child should go
  6. final int width = mRight - mLeft;
  7. int childRight = width - mPaddingRight;
  8. // Space available for child
  9. int childSpace = width - paddingLeft - mPaddingRight;
  10. final int count = getVirtualChildCount();
  11. final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
  12. final int minorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
  13. if (majorGravity != Gravity.TOP) {
  14. switch (majorGravity) {
  15. case Gravity.BOTTOM:
  16. // mTotalLength contains the padding already, we add the top
  17. // padding to compensate
  18. childTop = mBottom - mTop + mPaddingTop - mTotalLength;
  19. break;
  20. case Gravity.CENTER_VERTICAL:
  21. childTop += ((mBottom - mTop)  - mTotalLength) / 2;
  22. break;
  23. }
  24. }
  25. for (int i = 0; i < count; i++) {
  26. final View child = getVirtualChildAt(i);
  27. if (child == null) {
  28. childTop += measureNullChild(i);
  29. } else if (child.getVisibility() != GONE) {
  30. final int childWidth = child.getMeasuredWidth();
  31. final int childHeight = child.getMeasuredHeight();
  32. final LinearLayout.LayoutParams lp =
  33. (LinearLayout.LayoutParams) child.getLayoutParams();
  34. int gravity = lp.gravity;
  35. if (gravity < 0) {
  36. gravity = minorGravity;
  37. }
  38. switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
  39. case Gravity.LEFT:
  40. childLeft = paddingLeft + lp.leftMargin;
  41. break;
  42. case Gravity.CENTER_HORIZONTAL:
  43. childLeft = paddingLeft + ((childSpace - childWidth) / 2)
  44. + lp.leftMargin - lp.rightMargin;
  45. break;
  46. case Gravity.RIGHT:
  47. childLeft = childRight - childWidth - lp.rightMargin;
  48. break;
  49. default:
  50. childLeft = paddingLeft;
  51. break;
  52. }
  53. childTop += lp.topMargin;
  54. setChildFrame(child, childLeft, childTop + getLocationOffset(child),
  55. childWidth, childHeight);
  56. childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
  57. i += getChildrenSkipCount(child, i);
  58. }
  59. }
  60. }
	a) LinearLayout中的子视图有两种布局方式,一个是纵向的,一个是横向的,这里我们以纵向的分析。
	b) 获得子视图的宽度。
	c) 根据父视图中的grarity属性,来判断子视图的起始位置。
	d) 开始for()循环,为每个子视图分配位置。对于每个子视图首先取出子视图的LayoutParams属性,并且获得gravity的值。根据gravity的值确定水平方向的起始位置,三种值分别为:LEFT,CENTER_HORIZONTAL和RIGHT.接着调用setChildFrame(),该方法内部实际上就是调用child.layout()为子视图设置布局位置。

转载请说明出处:http://blog.csdn.net/ff20081528/article/details/17784911

时间: 2024-12-29 19:29:39

View工作原理(四)view的layout过程的相关文章

以PKI为基础的CA工作原理及 加密、解密过程

             以PKI为基础的CA工作原理及  加密.解密过程   PKI(Public Key Infrastructure ) 即"公钥基础设施",是一种遵循既定标准的密钥管理平台,它能够为所有网络应用提供加密和数字签名等密码服务及所必需的密钥和证书管理体系.简单来说,PKI就是利用公钥理论和技术建立的提供安全服务的基础设施.PKI技术是信息安全技术的核心,也是电子商务的关键和基础技术. 一个典型.完整.有效的PKI 应用系统至少应具有以下五个部分: 1) 认证中心CA

View的工作原理(二)——layout

1.当View的measure被确定后,会调用ViewGroup的layout方法,之后使用onLayout方法(同样也是系统未自动重写,要我们自己完成)遍历子View(根Measure的形式是一样得)与Measure不同的时候,允许重写layout()方法. 分析layout源码:(P194 ①) 原理:通过setFrame方法设定View的四个顶点的位置,接着调用onLayout方法确定子元素的位置. 以LinearLayout的onLayout方法(Vertial):遍历子元素的layou

《Linux设计与实现》笔记——系统调用工作原理、添加系统调用的过程

系统调用的意义 为了和用户空间上的进程进行交互,内核提供的提供的一组接口. 应用程序通过这组接口访问硬件和其他操作系统资源. 完成对硬件和资源访问的控制.安全.可靠,多任务.虚拟必须 硬件设备的抽象(提供设备的独立性). 异常,陷入,系统调用 : 用户空间进入内核空间的三种方式 原理 sys_write会根据系统write输出的文件,调用相应struct file ,operations中的write方法. 添加系统调用的过程 以kernel 2.6.11为例 long my_syscall(i

关系型数据库的工作原理(四)

查询优化: 现代数据库都使用一种基于成本优化(参见第一部分)的方式进行优化查询,这种方式的思路是给每种基本运算设定一个成本,然后采用某种运算顺序总成本最小的方式进行查询,得到最优的结果. 为简化理解,对数据库的查询重点放在查询时间复杂度上,而不考虑CPU消耗,内存占用与磁盘I/O,且相比与CPU消耗,数据库瓶颈也更多在磁盘I/O. 索引 B+树.bitmap index等都是常见的索引实现方式,不同的索引实现有不同的内存消耗.I/O以及CPU占用.一些现代数据库还可以创建临时索引. 获取(数据)

DNS查询的工作原理

二.DNS查询的工作原理 1.DNS查询过程按两部分进行     1.名称查询从客户端计算机开始, 并传送给本机的DNS客户服务程序进行解析     2.如果不能再本机解析查询, 可根据设定的查询DNS服务器来解析名称. 2.具体工作过程     1.DNS客户端 --客户端DNS缓存 查找主机文件(有信息)-- 返回信息给DNS客户端     2.DNS客户端 --客户端DNS缓存 查找主机文件 (无信息)--*DNS服务器         ==1区域          ==2通过根目录提示文

oracle 索引聚簇表的工作原理

作者:Richard-Lui 一:首先介绍一下索引聚簇表的工作原理:(先创建簇,再在簇里创建索引,创建表时指定列的簇类型) 聚簇是指:如果一组表有一些共同的列,则将这样一组表存储在相同的数据库块中:聚簇还表示把相关的数据存储在同一个块上.利用聚簇,一个块可能包含多个表的数据.概念上就是如果两个或多个表经常做链接操作,那么可以把需要的数据预先存储在一起.聚簇还可以用于单个表,可以按某个列将数据分组存储. 更加简单的说,比如说,EMP表和DEPT表,这两个表存储在不同的segment中,甚至有可能存

搜索引擎基本工作原理

搜索引擎的基本工作原理包括如下三个过程:首先在互联网中发现.搜集网页信息:同时对信息进行提取和组织建立索引库:再由检索器根据用户输入的查询关键字,在索引库中快速检出文档,进行文档与查询的相关度评价,对将要输出的结果进行排序,并将查询结果返回给用户. 工作原理编辑 1.抓取网页.每个独立的搜索引擎都有自己的网页抓取程序爬虫(spider).爬虫Spider顺着网页中的超链接,从这个网站爬到另一个网站,通过超链接分析连续访问抓取更多网页.被抓取的网页被称之为网页快照.由于互联网中超链接的应用很普遍,

Tomcat的结构及工作原理

Tomcat下有一个Server服务器,里面有多个service服务,每个service服务有两个核心组件:Connector和Container--工作原理(处理请求的过程) 用户点击网页内容,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得.2.Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应. 3.Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Hos

【Ceph浅析笔记】Ceph的工作原理

本章主要对Ceph的工作原理进行介绍. 寻址过程 如果Client来了一个请求,不管个请求是读还是写都需要先寻址,才能找到数据应该放哪里或者说需要从哪里去. 之前我们说过Ceph的寻址方式是基于计算的,这样就避免的查表,也避免了使用一个单独的元数据服务器. 概述 对于Client传来的一个File,为了方便处理,我们可以将其分割为若干大小相同的小块Object. 然后可以将这些Object映射到OSD上,如果使用一种固定的映射算法,则一个Object每次都会固定的映射到一组OSD上,那么如果这个