android view : 绘制
说到绘制,其实就是如何把一个view的对象,变成手机上可视的图形。很多人总结3个过程:测量,布局,绘制。这也是所有的要显示图形的程序所应该抽象的3个步骤,测量就是测量出你view的大小,布局就是要显示在屏幕的哪个坐标位置,绘制就是把图形画到屏幕上。view和viewgroup的处理方法是不同的。
view:
1.measure:要测量应该考虑的就是view的大小,重点看view中的measure,首先是判断是否有必要测量view中有一个mprivateflags是一个标志位,标志了view的所有的状态表示。判断是否要FROCE_LAYOUT。然后判断现在的测量的大小和一个之前测量的大小是否一样。之前的测绘mOldWidthMeasurSpec和mOldHighMeasurSpec存储。初始值为Integer.MINVALUE.
tip:谈到标志的存储,这里有很大的学问,要知道并不是所有的标志都是boolean存储。还可以使用int,而且int要保存的标志位和他的位数是一致的,也就是int有32位,他就可以表示32个标志。怎么做到?在java中位的操作就是用| & 和&~。当我们增加一个标志位的时候使用|,判断一个标志使用&,消除一个标志使用&~。int的每一个bit都可以表示一个标志位,首先你要定义各种标志位使用0x0100 0000这样,然后假如有一个状态值为0x0100 0000 和默认值一样&之后就是非0的值,在java中Boolean必须使用 == 来判断,所以mPrivateFlags & FORCE_LAYOUT就是判断是否含有这个标志位。当你要添加一个标志位的使用就要使用| 。删除使用&~。这样的操作在android flag中比比皆是。这样做的好处是什么?不用定义多个标志位。仅仅使用一个int值就可以了。另外还相对于boolean减少了空间。(关于boolean占用多少个字节来说,有人说1byte,有人说1bit。虚拟机实现不同,也有一定关系。但是大量的标志位的时候还是使用int的这种位操作更加靠谱)
mOldHighMeasurSpec为什么将这两个旧的宽高设置为0?含义仅仅是0?判断完,当需要测量的时候,就调用了 onMeasure(widthMeasureSpec, heightMeasureSpec);细心一点就会想为什么不使用mWidth这样容易记的东西?而是使用冗长的名称?onmeasure方法里面就使用了一个setMeasuredDimension来设置宽高,在view中实际使用mMeasuredWidth和mMeasuredHeight来表示view的宽高。所以即使是我们继承了view也要使用setMeasuredDimension来设置测量好的宽高。带着所有的疑问,让我们重点关注一个view的内部静态类MeasureSpec。
MeasureSpec:
这是一个测量中的最关键的类,他把一个int表示了两个概念:模式,大小。模式这里面定义了3种模式:UNSPECIFIED,EXACTLY,AT_MOST用来分别表示未知,已测量,最大可用。大小就是测量的大小。当你传递进来一个数值的时候这个时候包含了两种信息:如果是未知,就需要你亲自测量。如果是已知,就使用测量好的,如果是最大可用,就用可使用最大值。
叙述完概念之后,看一下实际的数值UNSPECIFIED是0x0000 0000,EXACTLY是0x1000 0000,AT_MOST是0x2000 0000.知道为什么我这么写出来吗?对又是标志位的使用,这里为什么可以把int表示为mode和size两种概念,就是前两位表示模式,后30为表示大小。这里面还定义了两个辅助的常量就是MODE_SHIFT是30也就是说后30位表示大小,MODE_MASK表示“面具”就是说0x3000 0000为什么说是面具?其实是英语含义,我这么叫他是因为他可以除去模式只留下大小信息。
模式:首先来说如何获取一个模式?measureSpec & MODE_MASK,之前就说过使用&来判断有无标志位。大小:获取大小的方法一样measureSpec & ~MODE_MASK消除了标志位就是大小信息。那么怎么生成一个这样的measureSpec ?mode+size就可以了。
这样应该理解了MeasureSpec,在onmeasure里面有一个getDefaultSize的方法,这个方法就是默认的处理测量的,在UNSPECIFIED的时候使用传递来的值,在EXACTLY的时候使用测绘值,最大可用也是默认值(也就是measureSpec附带的size大小)。那传递值是?getSuggestedMinimumWidth这个里面有,也就是说默认我不测绘的时候会有一个默认的宽高。就是背景大小和mMinWidth比较。背景实际是一个bitmap也就是看一下这个背景的大小。然后和xml中的mMinwidth设置的值做一个比较。最小的就是默认值。也正是AT_MOST的含义,求出最大的可用宽高。
tip:那么什么时候会传递EXACTLY?什么时候传递AT_MOST,下面的仅仅是rootview的策略!就是decroview
case ViewGroup.LayoutParams.MATCH_PARENT:
// Window can't resize. Force root view to be windowSize.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
break;
case ViewGroup.LayoutParams.WRAP_CONTENT:
// Window can resize. Set max size for root view.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
break;default:
// Window wants to be an exact size. Force root view to be that size.
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
break;
也就是说既然view必须设置LayoutParams。这里就是他的用途,当你是一个填充窗体的时候,那么你的view所占据的大小就是确定的并且是父viewgroup大小windowSize(因为只有在viewgroup中才会有view)。在包裹内容的时候,view的大小就是可用的最大大小也是windowsize。这里面就是说无论是什么都要给rootview一个windowsize,真正的布局划分和测量在viewgroup中!
到处为止measure就算完了。有点乱。其实就是measure回调onMeasure,其实最关键的并不在这里,而在viewgroup中。
2layout:这个是布局,布局就是把位置表示出来,注意的是这里的位置view中的mLeft等变量表示的,但是却不是屏幕上的绝对位置,是基于父类的位置,这个概念很重要。关系到了layout的使用首先setFrame来看一下是否是布局变动了,如果变动了就设置到变量中,这里的onlayout就比较鸡肋了,仅仅是提供了一个回调。我们要改变布局的时候可以直接使用layout,而不用等待onlayout的回调,其实主要是setframe,但是这个是受保护的,我们不可以随便使用。
tip: 关于这个layout最关键的其实是我们如何使得view进行移动的一个方法,这里还有一个方法叫做scrollto和scrollby.这些概念都是基于view怎么布局的问题,一个view要想布局就要知道父布局,然后进行偏移,这个偏移是mScrollX和mScrollY通过scrollTo来移动的,表示把view移动到基于当前view的x和y处(坐标原点在view左上角),然后这个x,y就被设置为了mScrollX和mScrollY。scrollby是调用了scrollTo(mScrollX + x, mScrollY + y);也就是说是基于当前的位置再移动x,y。
了解了这个概念之后你就可以自定义移动view了不要以为移动只可以用scrollTo,还有就是layout也可以,但是layout实际上移动的是view在viewgroup中的位置,而scrollTo是移动的view在view本身的布局的位置。影响view在屏幕中的绝对位置的有3个:mLeft,mScrollX,paddingLeft也就是说mLeft是layout控制,mScrollX是由ScrollTo控制。主要就是利用这两个东西来控制view。所以一个view只能在父布局中移动。但是你要明白的是你的界面控制是你来控制的,所有移动都可以实现。只是布局设计的问题。
3draw:绘制,首先是绘制背景mBGDrawable,确定背景大小,然后执行canvas.translate(scrollX, scrollY);background.draw(canvas);canvas.translate(-scrollX, -scrollY);好好想一下这一个,你就会体会出view是无穷去界的,而我们的眼睛限制了我们。你要知道的所有的东西都在画布canvas上,这个是进行了画布的移动。画上了背景在把画布移动回去。也就是说canves是无穷无界的。最后执行dispatchdraw其实就是画view的各个控件。这个方法在子类中扩展
viewgroup:
1。measureChildren:里面调用measureChild。首先还是检验模式,当为确定或者是最大值得时,无论包裹内容还是占据父窗体都是传递来的大小。当无法确定的时候,使用的是0.实际上在继承了viewgroup之后,你可以复写onmeasure方法,进行自定义的测量。
2.layout,这个viewgroup本身就没有实现,由于是交给子类实现的,所以根本就设为空方法。
3.draw viewgroup管理的是view的布局和大小,本身是没有太多的绘制,也没有实现父类。都交给了子类。
关于绘制view,更加关键的其实是实践,多布局和绘制一些view和viewgroup。
android view : 绘制的更多相关文章
- 简单研究Android View绘制三 布局过程
2015-07-28 17:29:19 这一篇主要看看布局过程 一.布局过程肯定要不可避免的涉及到layout()和onLayout()方法,这两个方法都是定义在View.java中,源码如下: /* ...
- 简单研究Android View绘制一 测量过程
2015-07-27 16:52:58 一.如何通过继承ViewGroup来实现自定义View?首先得搞清楚Android时如何绘制View的,参考Android官方文档:How Android Dr ...
- Android View绘制原理分析
推荐两篇分析view绘制原理比较好的文章,感谢作者的分享. <Android应用层View绘制流程与源码分析> <View 绘制流程>
- Android View绘制过程
Android的View绘制是从根节点(Activity是DecorView)开始,他是一个自上而下的过程.View的绘制经历三个过程:Measure.Layout.Draw.基本流程如下图: per ...
- Android View绘制流程
框架分析 在之前的下拉刷新中,小结过触屏消息先到WindowManagerService(Wms)然后顺次传递给ViewRoot(派生自Handler),经decor view到Activity再传递 ...
- Android View绘制13问13答
1.View的绘制流程分几步,从哪开始?哪个过程结束以后能看到view? 答:从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程.draw ...
- Android View 绘制过程
Android的View绘制是从根节点(Activity是DecorView)开始,他是一个自上而下的过程.View的绘制经历三个过程:Measure.Layout.Draw.基本流程如下图: per ...
- Android View 绘制刷新流程分析
Android中对View的更新有很多种方式,使用时要区分不同的应用场合.1.不使用多线程和双缓冲 这种情况最简单,一般只是希望在View发生改变时对UI进行重绘.你只需显式地调用View对 ...
- Android View 绘制流程(Draw) 完全解析
前言 前几篇文章,笔者分别讲述了DecorView,measure,layout流程等,接下来将详细分析三大工作流程的最后一个流程——绘制流程.测量流程决定了View的大小,布局流程决定了View的位 ...
- 简单研究Android View绘制二 LayoutParams
2015-07-28 17:23:20 本篇是关于LayoutParams相关 ViewGroup.LayoutParams文档解释如下: LayoutParams are used by views ...
随机推荐
- Python:list用法
list是一种有序的集合,可以随时添加和删除其中的元素. 定义 空list >>> a_list=[] >>> a_list [] 普通 >>> ...
- Angularjs Controller间通信的几种方法
先说最简单的,适合简单数据 一.使用controller as <body ng-controller="ParentCtrl as parent"> <inpu ...
- PHP redis 批量操作
参考网站 phpredis扩展 :https://github.com/phpredis/phpredis#pconnect-popen 命令参考:http://doc.redisfans.com ...
- W.Richard Stevens sock program
在<TCP/IP卷一>中有一个程序sock,Stevens的主页上有,但是在LINUX下通常无法工作(那时还没有LINUX),经过百度,发现http://www.icir.org/chri ...
- hadoop 2.6配置记录
本地hadoop配置 1)core-site.xml <?xml version="1.0" encoding="UTF-8"?> <?xml ...
- Bootstrap<基础十五> 输入框组
Bootstrap 支持的另一个特性,输入框组.输入框组扩展自 表单控件.使用输入框组,可以很容易地向基于文本的输入框添加作为前缀和后缀的文本或按钮. 通过向输入域添加前缀和后缀的内容,您可以向用户输 ...
- Java深度历险(五)——Java泛型
作者 成富 发布于 2011年3月3日 | 注意:QCon全球软件开发大会(北京)2016年4月21-23日,了解更多详情!17 讨论 分享到:微博微信FacebookTwitter有道云笔记邮件 ...
- UIApplication详解
每个app有且只有一个UIApplication对象,当程序启动的时候通过调用UIApplicationMain方法得到的.可以通过sharedApplication方法得到. UIApplicati ...
- Microsoft Azure Project Oxford 体验
2015年4月29日,微软在Build 2015大会上发布了一个震撼人心的项目: Project Oxford, 可以帮助直接实现图像理解.人脸识别.语音识别.语音合成等功能.虽然说这是号称研究院的项 ...
- c——I/O Multiplexing笔记
1. select第一个参数为最大FD(int)+1,因为虽然select参数里有三个set,但分配到的fd值是不会重复的,当select检查fd可用时(可读或可写或异常),会遍历进程fd表,这时遍历 ...