android绘制view的过程
1 android绘制view的过程简单描述
简单描述可以解释为:计算大小(measure),布局坐标计算(layout),绘制到屏幕(draw);
下面看看每一步的动作到底是什么,
第一步:当activity启动的时候,触发初始化view过程的是由Window对象的DecorView调用View(具体怎样从xml中读取是用LayoutInflater.from(context).inflate)对象的 public final void measure(int widthMeasureSpec, int heightMeasureSpec)方法开始的,这个方法是final类型的,也就是所有的子类都不能继承该方法,保证android初始化view的原理不变。具体参数类值,后面会介绍。
第二步:View的measure方法 onMeasure(widthMeasureSpec, heightMeasureSpec),该方法进行实质性的view大小计算。注意:view的大小是有父view和自己的大小决定的,而不是单一决定的。这也就是为什么ViewGroup的子类会重新该方法,比如LinearLayout等。因为他们要计算自己和子view的大小。View基类有自己的实现,只是设置大小。其实根据源码来看,measure的过程本质上就是把Match_parent和wrap_content转换为实际大小
第三步:当measure结束时,回到DecorView,计算大小计算好了,那么就开始布局了,开始调用view的 public final void layout(int l, int t, int r, int b),该还是也是final类型的,目的和measure方法一样。layout方法内部会调用onlayout(int l, int t, int r, int b )方法,二ViewGroup将此方法abstract的了,所以我们继承ViewGroup的时候,需要重新该方法。该方法的本质是通过measure计算好的大小,计算出view在屏幕上的坐标点
第四步:measure过了,layout过了,那么就要开始绘制到屏幕上了,所以开始调用view的 public void draw(Canvas canvas)方法,此时方法不是final了,原因是程序员可以自己画,内部会调用ondraw,我们经常需要重写的方法。
以上就是view的大概工作过程,当然了,只是概述,细节多成马了!!!!!
2 measure的过程
public final void measure(int widthMeasureSpec, int heightMeasureSpec)的参数来源及代表的意思
这个两个参数都是有父view传递过来的,也就是代表了父view的大小。其实说大小不太对,应该说是建议“规格”。他有两部分组成,
第一部分:高16位表示MODE,定义在MeasureSpec类中,有三种类型,
(1) MeasureSpec.EXACTLY:表示确定大小,父元素决定子元素的确切大小 ,子元素将被限定在给定的边界里而忽略它本身大小
(2) MeasureSpec.AT_MOST:表示最大大小,子元素至多达到指定大小的值。
(3) MeasureSpec.UNSPECIFIED:不确定。父元素不对子元素施加任何束缚,子元素可以得到任意想要的大小
第二部分:低16位表示size,既父view的大小,
这就是为什么,我们在重写onmeasure方法是需要:
int specMode = MeasureSpec.getMode(spec);
int specSize = MeasureSpec.getSize(spec);
这样调用,因为MeasureSpec知道怎么读取。对于根view(并不是我们在xml中声明的第一个元素),而是系统的Window对象的decorVIew对象。Mode一般都为MeasureSpec.EXACTLY ,而size分别对应屏幕宽,高。也就是Window第一次掉用的view(这个view才是Xml中声明的第一个元素),一般都是这个值,而对于子view来说,这连个值就是你在xml定义的属性 android:layout_width和android:layout_height这个,当然了上面说过view的大小是有父view和子view共同决定的,所以这样有点不对,但是来源于这两个值。意思明白了,我们看看measure里边做什么了 .
MeasureSpec类怎么使用?
通常在view组件的onMeasure方法里面调用.
它常用的三个函数:
1.static int getMode(int measureSpec):根据提供的测量值(格式)提取模式(上述三个模式之一)
2.static int getSize(int measureSpec):根据提供的测量值(格式)提取大小值(这个大小也就是我们通常所说的大小)
3.static int makeMeasureSpec(int size,int mode):根据提供的大小值和模式创建一个测量值(格式)
3 .measure方法内部操作过程
调用 onMeasure(widthMeasureSpec, heightMeasureSpec),将父view的建议大小和规格传入,view类自己的onmeasure方法,只是根据xml中配置的大小初始化大小 ,这个就不分析了,重要的我们看看viewGroup中的onMeasure方法,ViewGroup类中没有处理该方法,一般在他的子类中处理,比如LinearLayout中,我们以Linearlayout作为分析类。
•Linearlayout类的onMeasure方法分两种情况处理,1:重置排序,2:水平排序,这个大家都知道,我们分析重置排序,
•获取所有的子view数量,对每个子view开始处理,如果子view是GONE的,则直接跳过
•在LinearLaout.measureVertical方法中,首先:获取该子view的LayoutParams,在xml中定义的参数,将通过layout_weight定义的值累加到变量totalWeight中,所有的权重,然后判断如果view的height设置为零,但weight设置的大于0,则将height的值设置为LayoutParams.WRAP_CONTENT这个值,其他的不处理
•然后调用measureChildWithMargins方法,这个做的处理包括:计算子view的measureSpec,即MODE和SIZE,调用方法为:getChildMeasureSpec,调用两次,分别 计算宽和高,getChildMeasureSpec内部根据父view的Measure和子view的layout_width和layout_height属性计算子view的measure
getChildMeasureSpec计算子view的measure,总结如下:
1.如果在xml中指定了子view的具体大小,那么计算结果不管父的measure是什么,结果都是EXACITY+child_size,
2.如果子view的height指定的值为FILL_PARENT,则返回的结果为:EXACITY+size,原因很简单:因为FILL_PARENT的意思是充满这个父view,所以返回的子view的measure就是view的大小!
3.如果子vide的大小为wrap_content,那么返回的结果都为At_most+size,原因是:最大不能超过父view的大小。
•子view的measure确定好以后,然后调用子view的measure方法,如果子view是View对象,则该view的大小测量结束,开始下一个子view的循环,如果子view是ViewGroup那么,又开始一个新的递归,处理逻辑和上面一样,值得所有的view对象测量结束。
•LinearLayout会在每个他的直接子view测量结束后,将该子view的高度累加到变量mTotalLength,其其实应该叫mTotalHeight更合适,但是为了和wight同一,所以命名为这个(这个过程不处理:父view的大小指定为具体值和fill_parent,且子view的高度指定为0和子viewweight值大于的)。
•所有的子view测量结束后,才开始对layout_weight计算,这样我们可能想到,如果父view已经被占满了,那么有可能layout_weight大于0的view对象是不会显示的,而计算layout_weight的方法也很简单,就是用总高度减去上面分析完mTotalLength的值,就是剩下,然后去平分给view对象,注意计算权重时优先去android:android:weightSum(LinearLayout的xml属性)的值,如果不设置该值会计算和,所以该值既然设置了,就一定要子view的weight的总和相等,否则平分可能不能得到预期效果,分析一个例子吧:
<LinearLayout android:layout_width="fill_parent"
android:layout_height="200dp"
>
<TextView android:layout_width="fill_parent"
android:layout_height="100dp"
android:layout_weight="1"
/>
<TextView android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
</LinearLayout>
上面这个例子再计算第一个TextView的时候,根据android:layout_height="100dp" 值,确定高度为100dp,计算第二个TextView的时候,由于android:layout_height="0"为0,所以不计算其高度,等到计算weight的时候才计算,当计算weight的时候,千万别认为第一个TextView已经计算过了,就不计算了,还是计算的,计算过程如下:第一个分配了100dp,还剩100dp,所以两个textview各分50dp,所以第一个TextVIew的 150dp,第二个就为50dp
至此,view的measure就结束了,所有的view值都结束了,大家可能发现,这个过程只用了几个属性: android:layout_width,android:layout_height,android:layout_weight还有marger和pading,其他的多数属性都在ondraw时候使用,
android绘制view的过程的更多相关文章
- 【转】Android绘制View的过程研究——计算View的大小
Android绘制View的过程研究——计算View的大小 转自:http://liujianqiao398.blog.163.com/blog/static/18182725720121023218 ...
- Android 绘制view的小知识点
[onMeasure] 直接继承view或ViewGroup的自定义控件需要重写onMeasure方法并设置wrap_content时的自身大小,否则在布局中使用wrap_content就相当于mat ...
- Android 自定义View及其在布局文件中的使用示例(三):结合Android 4.4.2_r1源码分析onMeasure过程
转载请注明出处 http://www.cnblogs.com/crashmaker/p/3549365.html From crash_coder linguowu linguowu0622@gami ...
- Android绘制优化(一)绘制性能分析
前言 一个优秀的应用不仅仅是要有吸引人的功能和交互,同时在性能上也有很高的要求.运行Android系统的手机,虽然配置在不断的提升,但仍旧无法和PC相比,无法做到PC那样拥有超大的内存以及高性能的CP ...
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
Android中View的绘制过程 onMeasure方法简述 附有自定义View例子 Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android fr ...
- 【转】Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点. 绘制过程从布 ...
- android 中view的绘制过程
view的绘制过程中分别会执行:onMeasure(会多次)计算view的大小,OnLayout(),确定控件的大小和位置 onDraw()绘制view 当Activity获得焦点时,它将被要求绘制自 ...
- 深入理解 Android 之 View 的绘制流程
概述 本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定 ...
- Android中View绘制流程以及invalidate()等相关方法分析
[原文]http://blog.csdn.net/qinjuning 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简 ...
随机推荐
- 基于HTML5的WebGL呈现A星算法3D可视化
http://www.hightopo.com/demo/astar/astar.html 最近搞个游戏遇到最短路径的常规游戏问题,一时起兴基于HT for Web写了个A*算法的WebGL 3D呈现 ...
- Guid算法与标识列(自动增长字段)在表中的应用
<<1>>int(bigint)+标识列(自动增长字段) 用标识列实现字段自增可以避免并发等问题.不需开发人员自己控制自增,用标识列的字段在Insert的时候不用指定主键的值. ...
- 相关子查询【SQL Server】
查询book表中大于该类图书价格平均值的图书信息 先将第一条记录的类编号的值为2代入子查询中,子查询为 select avg(price) from book b where b.id=2 则得到类编 ...
- C#以管理员身份运行程序
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; names ...
- web前端学习笔记---scrollWidth,clientWidth,offsetWidth的区别
通过一个demo测试这三个属性的差别. 说明: scrollWidth:对象的实际内容的宽度,不包边线宽度,会随对象中内容超过可视区后而变大. clientWidth:对象内容的可视区的宽度,不包滚动 ...
- “Win10 UAP 开发系列”之 在MVVM模式中控制ListView滚动位置
这个扩展属性从WP8.1就开始用了,主要是为了解决MVVM模式中无法直接控制ListView滚动位置的问题.比如在VM中刷新了数据,需要将View中的ListView滚动到顶部,ListView只有一 ...
- 为什么要用 Bootstrap
[Bootstrap](http://hovertree.com/menu/bootstrap/) 是由两个 twitter 员工开发并开源的前端框架,非常火爆,而如此火爆自然有它的道理,在我们团队的 ...
- GNOME on Arch Linux
Arch Linux上Gnome桌面截图欣赏: 相比而言,Debian的壁纸一直好像格调不够啊:
- Typecho 新浪登陆插件 Sinauth
花了点时间弄了一个插件. 代码地址:https://github.com/web3d/plugins/tree/master/Sinauth Typecho的扩展机制还是比较完善的,可以自行增加Act ...
- JWS ,JAX-WS ,JAX-RS,REST,Restlet,SOAP 相关概念
与 WebServices 相关的 J2EE 技术称为 JWS(Java WebServices),其中含有 JAX-WS.JAX-RS.JAXB.JAXR.SAAJ.StAX 等技术 支持 SOAP ...