刚过完自己的本命年,新的一年希望自己有个新的开始,祝自己在新的一年里一帆风顺,同时也祝广大的朋友们新年新气象,收获多多!
一、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()为子视图设置布局位置。

View工作原理(四)view的layout过程相关推荐

  1. view工作原理-计算视图大小的过程(onMeasure)

    view的视图有两种情况: 内容型视图:由视图的内容决定其大小. 图形型视图:父视图为view动态调整大小. ### measure的本质 把视图布局使用的"相对值"转化成具体值的 ...

  2. View工作原理(三)视图大小计算过程(measure过程)

    一.android中view的measure过程总概 视图大小计算的过程是从根视图measure()方法开始,接着该方法会调用根视图的onMeasure()方法,onMeasure()方法会对所包含的 ...

  3. View工作原理(一)事件传递原理详解

    版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 转载请说明出处:http://blog.csdn.net/ff20081528/article/details/17353869 ...

  4. View工作原理(二)导致View重建原因

    导致View重建的原因有三个: 1.视图本身内部状态变化引起重绘: 2.view树内部添加或者删除子view: 3.View本身的大小及可见性发生变化. 这三种情况最后都直接或者间接的调用到了三个方法 ...

  5. 预充电电路工作原理_研究电动汽车预充电过程

    2参数匹配分析 图3为预充电过程波形.加入预充电过程,K+先断开,使拥有较大阻抗的KP和R构成的预充电回路先接通,当预充电电路工作时,负载电容C上的电压Uc越来越高(预充电电流IP=(UB-Uc)/R ...

  6. 深入解析浏览器的幕后工作原理(四) DOM树

    下 转载于:https://www.cnblogs.com/menu/p/7059223.html

  7. 《Android开发艺术探索》读书笔记 (4) 第4章 View的工作原理

    本节和<Android群英传>中的第3章Android控件架构与自定义控件详解有关系,建议先阅读该章的总结 第4章 View的工作原理 4.1 初始ViewRoot和DecorView ( ...

  8. 【学习】Android中View的工作原理(上)——ViewRoot、DecorView、MeasureSpec

    初识ViewRoot和DecorView ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot完成 ...

  9. 安卓基础知识之View篇(四):View 事件滑动冲突解决方案

    安卓基础知识系列旨在简明扼要地提供面试或工作中常用的基础知识,让对安卓还不太熟悉的小伙伴更快地入门.同时自己在工作中,也没法完全记住所有的基础细节,写这样的系列文章,可以让自己形成一个更完备的知识体系 ...

最新文章

  1. oracle索引与mysql区别_MySQL和Oracle中的唯一性索引从差别(r12笔记第83天)
  2. 怎么通俗的理解Netty呢?
  3. 清华镜像:zookeeper
  4. 如何调整SAP HANA studio里的字体大小
  5. P1829-[国家集训队]Crash的数字表格/JZPTAB【莫比乌斯反演】
  6. 滴滴java开发面试题_Java开发经典面试题(十二)
  7. SqlServer学习之触发器
  8. 5g通用模组是什么_中国移动联合芯讯通发布5G终端、芯片及测试产业报告
  9. matlab做信号实验需要安装那些模块_无人机基于Matlab/Simulink的模型开发(连载一)...
  10. THREEJS - mousedown/mouseup等鼠标相关事件失效
  11. java堆栈_java线程的堆栈跟踪之jstack篇
  12. 线性电阻软件的伏安特性曲线测试,线性电阻和非线性电阻的伏安特性曲线
  13. 什么是汽车SOA架构?【长期更新】【800字】【原创】
  14. java音频剪辑_Java混剪音频
  15. FPGA——HLS简介
  16. L2-3 清点代码库 (25 分)(C/C++)
  17. ad服务器做虚拟化,为虚拟桌面准备AD服务器
  18. Scrapy爬取知乎用户信息(代理池,MongoDB,非分布式)
  19. 1003. Universal Travel Sites (35)解题报告
  20. ARM Rootkit

热门文章

  1. 【数字信号处理】序列傅里叶变换 ( 狄义赫利条件 | 序列傅里叶变换定义 )
  2. 【数字信号处理】线性常系数差分方程 ( 根据 “ 线性常系数差分方程 “ 与 “ 边界条件 “ 确定系统是否是 “ 线性时不变系统 “ 案例二 | 修改边界条件 | 使用递推方法证明 )
  3. 【Android 热修复】热修复原理 ( Dex 文件拷贝后续操作 | 外部存储空间权限申请 | 执行效果验证 | 源码资源 )
  4. 【错误记录】布局组件加载错误 ( Attempt to invoke virtual method ‘xxx$Callback android.view.Window.getCallback()‘ )
  5. 【Android 应用开发】Google 官方 EasyPermissions 权限申请库 ( 简介 | 权限申请处理细节 | 添加依赖 | 界面权限申请结果处理 | 权限申请结果回调接口 )
  6. php 二维数组排序详解: array_multisort
  7. [BZOJ 1879][SDOI 2009]Bill的挑战 题解(状压DP)
  8. 跟我一起用node-express搭建一个小项目(node连接mongodb)[三]
  9. 第20条:为私有方法名加前缀
  10. SharePoint 2013安装图文教程