《Android群英传》读书笔记
最近在找工作。。。话说北京这个时候的工作真不好找啊。。。慢慢来吧,总会找到的,最近在拜读一本大作,叫做《Android群英传》是大神写的。是一本好书。这本书讲了很多的高级的知识,真是太牛X了。今天看了这本书的Android控件架构与自定义控件,做一个读书笔记
Android控件架构
Android中的每一个控件都在界面中占得一块矩形的区域,在Android中控件分为两类:
ViewGroup:作为父控件其包含很多的子控件。并管理其包含的View控件。ViewGroup使得整个界面上的控件形成了一个树形结构——控件树,上层的控件负责下层子控件的测量和绘制。并传递交互事件。使用findViewbyId()就是在控件树中以树的深度优先遍历来查找对应元素
View控件就是包含在父控件下的控件。由父控件来管理
分析setContentView()
每个Activity包含一个Window对象,Window对象通常由PhoneWindow来实现。PhoneView将一个DecorView作为应用窗口的根View.(顶层视图),并封装了一些窗口操作的通用方法。DecorView将要显示的内容呈现在了phoneWindow上,所有的View的监听事件,都通过WindowManagerService来接受。并通过Activity对象来回调相应的onClicklistener.
在显示上,界面分为两部分 一个是TitleView 一个是ContentView。ContentView是一个ID为Content的Framelayout,我们的Activity布局文件就是设置在这样一个Framelayout中。
再显示界面中也就是DecorView中装载了一个线性布局。我们最常用的布局比如上面显示一个TitleBar 下面是Content的布局就是作为线性布局显示在界面上的。这里也能说明如果我们要设置全屏的话为什么requestWindowFeature(WindowFEATURENOTITLE)要设置在setContentView()前面。
在代码中,当程序在onCreate()方法中调用setContentView()方法后,ActivityManagerService会回调onResume()方法,此时系统才会把整个DecorView添加到PhoneWindow中并让其显示。完成绘制也就是说系统完成界面的绘制是在onResume()方法中完成的。
自定义View
ViewGroup测量
ViewGroup会管理其子View,其中一个管理项目就是管理子View的显示大小。ViewGroup的大小为wrap_content时,ViewGroup就需要对子View进行遍历。可以获得所有子View的大小。
ViewGroup在测量时通过遍历所有子View,从而调用子View的Measure方法来获得每一个子View的测量结果
View的布局
子View测量完毕后,需要将子View放到合适的位置,这时就会调用View的Layout过程。ViewGroup在执行Layout过程时,会同时遍历来调用子View的Layout方法。并指定具体显示位置。
View的测量
Android在绘制View前,必须对View进行测量,以确定显示的大小。测量的过程在onMeasure()方法中进行
Android提供了一个MeasureSpec类,来帮助我们测量View.MeasureSpec是一个32位的int值。其中高2位为测量的模式,后面的为测量的大小。(为提高效率使用位运算)
测量的模式:
EXACTLY:
当我们使用精确值模式,指定大小或者match_parent时,系统使用的是EXACTLY
AT_MOST:
最大值模式,当我们使用wrap_content时,要求此时控件的尺寸只要不超过父控件允许的最大尺寸即可
UNSPECIFIED:
绘制自定义View的时候使用,不指定大小
View默认的onMeasure()方法只支持EXACTLY模式,如果自定义控件不写onMeasure()方法的时候,就只能使用EXACTLY模式。
如果你想控件可以响应指定的具体值或者是matchparent属性,可以不重写onMeasure()方法
如果控件不指定大小 wrapcontent时就必须要重写onMeasure()方法
通过MeasureSpec这个类,我们可以获取View的测量模式和想要绘制的大小
我们可以从MeasureSpec对象中取出测量的模式和测量值的大小
int mode = MeasureSpec.getMode(widthMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
通过判断测量的模式,可以得出不同的测量值
- 当SpecMode为EXACTLY模式:
直接使用指定的specSize即可 - 其它两种模式时:
需要给它一个默认的大小 - ATMOST模式: 想要支持wrapcontent 需要取出我们指定的大小与specSize中最小的一个来作为最后的测量值
View绘制
测量好View后,就可以重写onDraw()方法,并在Canvas上绘制所需要的图形
绘制所需要的Canvas对象
要想绘制相应的图像,就必须在Canvas上绘制 onDraw()中有一个参数就是Canvas canvas对象 使用这个Canvas对象就可以进行绘图 创建一个Canvas对象时候需要传进去一个Bitmap对象,这样你调用所有的Canvas对象的drawXXX方法都将发生在这个bitmap上
自定义View
View中的重要的回调方法
- onFinishInflate() xml加载组件后回调
- onSizeChanged() 组件大小改变时回调
- onMeasure() 回调该方法来进行测量
- onLayout()回调该方法来确定显示的位置
- onTouchEvent 监听到触摸事件的回调
自定义View的方式
对现有组件扩展
继承现有的组件,添加自己的功能 onDraw()方法
创建复合控件
继承一个ViewGroup,配置属性
重写View来实现全新控件
继承View 并重写它的onDraw()、onMeasure()方法来实现绘制,重写onTouchEvent()处理点击事件
自定义ViewGroup
继承ViewGroup并添加子View,ViewGroup管理子View的测量 布局 绘制等