原文链接

创造优秀的用户体验是我们开发者的主要目标之一.为此, 我们首先要了解系统是如何工作的, 这样我们才可以更好的与系统配合, 从它的优点中获益, 规避它的缺陷.


之前关于Android渲染过程的文章

这次我们主要关注Measure/Layout(测量和布局)的阶段, 这些阶段决定了视图的大小和位置, 以便于我们能够绘制它.

Step 1: Measure 测量

目标: 确定是图的大小

视图的大小包含其子视图的大小, 且必须符合其父视图的要求

视图的大小由2个方面决定:

  • 测量宽度与测量高度 - 视图在其父视图中想要占据多大空间.这是此阶段我们需要的大小.
  • 宽度与高度(也就是绘制高度与绘制宽度) - 在绘制和布局阶段, 视图在屏幕上视图的大小. 这个大小会在step2中算出.

How does it work?

  • 自顶向下递归的遍历view树.
  • 每个视图将规格传递给子视图.

如何实现?父视图通过MeasureSpec类的三种选项之一来决定子视图的宽高:

  1. UNSPECIFIED - 未指定, 子视图可以获得任意大小
  2. EXACTLY - 指定, 子视图应该有指定大小
  3. AT_MOST - 最大, 子视图最大可达到某个值

每个视图的宽高设置由ViewGroup.LayoutParams的3种选项决定:

  1. 一个明确的数字
  2. MATCH_PARENT 子视图想要和父视图一样大
  3. WRAP_CONTENT 子视图想要和自身的内容一样大
  • 测量过程在onMeasure(int widthMeasureSpec, int heightMeasureSpec)函数中完成

  • 当这个函数返回时, 每个视图都必须有measuredWidthmeasuredHeight(可由调用super()完成), 否则会抛出IllegalStateException.

Notice that this process sometimes a negotiation between a view and its children, and so measure() may be called more than once. More on that on a later post.

  • 注意这个过程有时需要视图和其子视图互相协商, 因此measure()方法可能会被调用不止一次.

Since the traversal is top down, and each parent tells its children the requirements, we end up with our goal achieved:

Each view’s measured size includes its children size, and fit its parent requirements.

因为遍历是自顶向下的, 并且没个父视图告诉子视图其需求, 我们最终的目标是:

每个视图的计算大小包含了子视图的大小, 并符合其父视图的要求

Step 2: Layout 布局

目标: 卫士图及其子视图设定位置和大小(绘制宽度和绘制高度)

  • 与step1类似: 自顶向下递归遍历视图树.
  • 每个父视图通过上一个计算的大小定位其所有子视图的位置.
  • 定位由onLayout(boolean changed, int left, int top, int right, int bottom)方法完成, 其中left, top, right, bottom是相对于其父视图的.
  • 当重写onLayout()方法时, 必须调用每个子视图的layout()方法.

Step 3: Draw 绘制

  • 当大小和位置都确定之后, 视图可以据此绘制自己.
  • onDraw(Canvas)方法中Canvas对象生成(或者是更新)一系列OpenGl-ES命令(displayList)发送给GPU.

这就是绘制的过程! 但是当我们改变了视图的属性时发生了什么呢? 由动画, 用户输入, 或者我们决定改变他们的时候.


When things change… 当发生改变时

当视图属性改变是, 视图会通知系统. 取决于改变的属性, 视图调用下列之一:

  • invalidate - 此时只会调用视图的onDraw()
  • requestLayout() - 会传递到根视图, 然后调用整个过程(测量->布局->绘制)

对于需要布局的情况有一个经典的小例子: 我们在一个RelativeLayout中有两个关系相对的视图. 如果其中一个改变了大小 - 一定会导致另一个重新定位, 也可能导致父视图改变大小.所以我们改变了一个视图的属性, 导致了整个布局都过期了.

这种情况提醒我们高效的布局是很重要的, 这样布局才能流程的执行并且不会导致跳帧.

[译]Android view 测量布局和绘制的流程的更多相关文章

  1. Android View 测量流程(Measure)完全解析

    前言 上一篇文章,笔者主要讲述了DecorView以及ViewRootImpl相关的作用,这里回顾一下上一章所说的内容:DecorView是视图的顶级View,我们添加的布局文件是它的一个子布局,而V ...

  2. android View页面布局总结 最全总结(转)

    下面是我在工作中总结的内容,希望对大家有帮助. 一.布局 View的几种布局显示方式有下面几种:线性布局(LinearLayout).相对布局(RelativeLayout).表格布局(TableLa ...

  3. Android View之布局加载流程

    1.引言 最近准备重新学习下Android,加深理解,快速形成自己的知识结构体系.最先学习的就算View部分,从自定义View到Activty层次结构,到layout加载过程.等等都会看一遍,在此记录 ...

  4. android view:布局优化

    今天在图书馆看了一个android性能优化. 关于布局优化有几个小技巧: 1.尽量减少布局的嵌套,而使用相对布局,这样的话会减少布局对象的创建,并且可以再事件传递的时候减少传递嵌套. 2.使用incl ...

  5. Android View 绘制流程(Draw) 完全解析

    前言 前几篇文章,笔者分别讲述了DecorView,measure,layout流程等,接下来将详细分析三大工作流程的最后一个流程——绘制流程.测量流程决定了View的大小,布局流程决定了View的位 ...

  6. Android View 布局流程(Layout)完全解析

    前言 上一篇文章,笔者详细讲述了View三大工作流程的第一个,Measure流程,如果对测量流程还不熟悉的读者可以参考一下上一篇文章.测量流程主要是对View树进行测量,获取每一个View的测量宽高, ...

  7. Android面试收集录12 View测量、布局及绘制原理

    一.View绘制的流程框架 View的绘制是从上往下一层层迭代下来的.DecorView-->ViewGroup(--->ViewGroup)-->View ,按照这个流程从上往下, ...

  8. 简单研究Android View绘制三 布局过程

    2015-07-28 17:29:19 这一篇主要看看布局过程 一.布局过程肯定要不可避免的涉及到layout()和onLayout()方法,这两个方法都是定义在View.java中,源码如下: /* ...

  9. Android view的测量及绘制

    讲真,自我感觉,我的水平真的是渣的一匹,好多东西都只停留在知道和会用的阶段,也想去研究原理和底层的实现,可是一看到代码就懵逼了,然后就看不下去了, 说自己不着急都是骗人的,我自己都不信,前两天买了本& ...

随机推荐

  1. Kotlin——基础的函数/方法详解

    对于Kotlin中的函数来说,和JavaScript或者Lua这些语言很像,它有着这些语言的特性.但是也与这些语言就着许多不同之处.或许你更了解Java语言,然而对于Java语言来说,它不是不是闭包这 ...

  2. 关于.Net的知识和相关书籍

    a. DBCC DROPCLEANBUFFERS 清空缓存信息b. DBCC FREEPROCCACHE 从过程缓存中删除所有元素2. 引用两个和尚打水的故事,说明平时要注重积累,只有量变达到了才会形 ...

  3. Linux CentOS 安装MySql以及搭建MySql主从复制

    前言 在之前的博客中,有过几篇都写了关于mysql在linux下的搭建教程,可能以后还会再写,但是又不想重复在写, 于是便想单独将此抽出来,单独写成一篇博客,并详细记录一些安装过程以及遇到的问题解决办 ...

  4. mongodb: Remote server has closed the connection

    <?php function getMongoClient($seeds = "", $options = array(), $retry = 3) { try { retu ...

  5. Django学习-19-缓存

    由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5 ...

  6. 三十天学不会TCP,UDP/IP网络编程 - 绅士的开始

    经过了过年的忙碌和年初的懈怠一切的日子,我又开始重新更新了~这是最新的一篇~完整版可以去gitbook(https://www.gitbook.com/@rogerzhu/)看到. 如果对和程序员有关 ...

  7. freemarker字符串转换成日期和时间(十三)

    freemarker字符串转换成日期和时间 1.日期时间转换总结 (1)date用来转换为日期 (2)time用来转换为时间 (3)datetime用来转换为日期和时间 2.展示示例 <#--字 ...

  8. css设置居中的方案总结

    回想一下,自己平时项目里遇到的比较多的就是css如何让元素居中显示,其实差不多每种情况都遇到过,所采用的方法也都各有利弊,下面对这些方法来做个概括,对其中的坑点,也会一一指出来,希望能给遇到问题的同学 ...

  9. 招聘面试—关于Mysql的一点儿总结

    最近半年,作为部门的面试官之一,参加了许多次招聘面试.数据库知识,尤其是对数据的增删改查等操作是软件测试人员的基本功,是面试过程中的必考项.在这其中,有一道题,是我每次面试的必考题. 题目 以Mysq ...

  10. 【Uoj34】多项式乘法(NTT,FFT)

    [Uoj34]多项式乘法(NTT,FFT) 题面 uoj 题解 首先多项式乘法用\(FFT\)是一个很久很久以前就写过的东西 直接贴一下代码吧.. #include<iostream> # ...