View的工作原理
2016-07-27 10:54
465 查看
一、ViewRoot和DecorView
1、ViewRoot
1)ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均通过ViewRoot来完成。2)在Activity线程中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立连接。
3)View的绘制流程
-纵向:从ViewRoot的performTraversals开始->performMeasure->performLayout->performDraw
-横向:
-performMeasure->measure->onMeasure
-performLayout->layout->onLayout
-performDraw->draw->onDraw
2、DecorView
1)一般情况下,DecorView内部会包含一个LinearLayout,里面分为上下两部分,分别为标题栏和内容栏,我们设置布局的时候就是调用setContentView方法。2)DecorView是一个FrameLyout,View层的事件都先经过它,然后分发给子View。
二、MeasureSpec
1、概念
MeasureSpec代表一个32位的int值,高2位代表SpecMode,低30位代表SpecSize。1)SpecMode代表测量模式,有3种
-UNSPECIFIED:父容器不对View有任何限制,要多大给多大。一般用于系统内部。
-EXACTLY:父容器已经检测到View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值。对应LayoutParams中的match_parent和具体的数值。
-AT_MOST:父容器指定了一个可用大小即SpecSize,View的大小不能大于这个值。对应LayoutParams中的wrap_content。
2)SpecSize代表在某种测量模式下的规格大小。
2、MeasureSpec和LayoutParams的对应关系
1)DecorView其Measure由窗口尺寸和自身Layoutparams来决定。调用getRootMeasureSpec方法,返回MeasureSpec
-LayoutParams.MATCH_PARENT:窗口尺寸+EXACTLY。
-LayoutParams.WRAP_CONTENT:窗口尺寸+AT_MOST。
-默认:Layoutparams的尺寸+EXACTLY。
2)普通View
其Measure由父容器的MeasureSpec和自身Layoutparams来决定。调用getChildMeasureSpec方法,返回MeasureSpec
-parentSpecMode:EXACTLY
-childLayoutParams.dp/px:child尺寸+EXACTLY。
-childLayoutParams.match_parent:parent尺寸+EXACTLY。
-childLayoutParams.wrap_content:parent尺寸+AT_MOST。
-parentSpecMode:AT_MOST
-childLayoutParams.dp/px:child尺寸+EXACTLY。
-childLayoutParams.match_parent:parent尺寸+AT_MOST。
-childLayoutParams.wrap_content:parent尺寸+AT_MOST。
-parentSpecMode:UNSPCIFIED
-childLayoutParams.dp/px:child尺寸+EXACTLY。
-childLayoutParams.match_parent:0。
-childLayoutParams.wrap_content:0。
三、View的工作流程
1、measure过程
1)View的measure过程:-onMeasure:调用setMeasureDimension
-setMeasureDimension:设置View宽高的测量值,参数通过getDefaultSize获取。 -getDefaultSize:返回measureSpec中的specSize,也就是View测量后的大小,第一个参数通过getSuggestedMinimumWidth/getSuggestedMinimumHeight获取,第二个参数为measureSpec。
-getSuggestedMinimumWidth/getSuggestedMinimumHeight:如果View没有设置背景,返回android:minWidth这个属性所指定的值,可以为0;如果View设置了背景,返回的就是View在UNSPECIFIED情况下的测量宽高。
2)ViewGroup的measure过程
ViewGroup是一个抽象类,并没有定义其测量的具体过程,而是提供了一个measureChildren的方法,具体过程需要各个子类去实现。
3)获取View的宽高:
因为measure过程和Activity的生命周期不同步,所以在onCreate、onStart、onResume中不能保证绝对获取到。
-onWindowFocusChanged:View已经初始化完毕,可以获取到View宽高。
-view.post(runnable):post将一个runnable投递到消息队列的队尾,然后等待Looper调用此runnable的时候,View已经初始化好了。
-ViewTreeObserver:使用ViewTreeObserver的回调,比如OnGlobalLayoutListener这个接口,当View树的状态发生变化或者View树内部的View可见性改变时,onGlobalLayout方法将被调用,这时就可以获取到View宽高。
2、layout过程
1)首先通过setFrame方法设定View的四个顶点的位置2)调用onLayout方法,父容器确定子元素的位置。
3、draw过程
1)绘制背景:background.draw(canvas)2)绘制自己:onDraw
3)绘制Children:dispatchDraw
4)绘制装饰:onDrawScrollBars
注意:
1)一个View不需要绘制内容,那么标志位WILL_NOT_DRAW设为true,系统会自动进行优化。
2)默认情况下,View没有启用这个标志位,ViewGroup则默认启动。
3)当自定义控件继承自ViewGroup并且自身不具备绘制功能,就可以开启这个标志位,从而便于系统优化。
四、自定义View
1、自定义View的分类
1)继承View重写onDraw方法实现一些不规则的效果,但是需要自己处理wrap_content和padding这两种情况。
2)继承ViewGroup派生特殊的Layout
实现几个View组合的效果,但是需要自己处理ViewGroup的measure和layout过程。
3)继承特定的View
用于扩展已有的View,不需要自己处理wrap_content和padding这两种情况。
4)继承特定的ViewGroup
实现几个View组合的效果,不需要自己处理ViewGroup的measure和layout过程。
2、自定义中的注意事项
1)让View支持wrap_content和padding。2)尽量不要在View使用Handler。
3)View中如果有线程或者动画,需要及时停止。
4)处理好View中的滑动冲突。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories