您的位置:首页 > 运维架构 > 网站架构

Android 控件架构与自定义控件详解

2016-08-18 09:22 169 查看

架构:

PhoneWindow 将一个 DecorView 设置为整个应用窗口的根 View,这里面所有 View 的监听事件,都通过 WindowManagerService 来接收。DecorView 分为 TitleView 和 ContentView,ContentView 是一个 ID 为 content 的 FrameLayout

onCreate()
方法中调用
setContentView()
方法后,ActivityManagerService 会回调
onResume()
方法,此时系统才会把整个 DecorView 添加到 PhoneWindow 中,并让其显示出来,从而完成最终的界面绘制。

View 的测量:

测量 View 的类:MeasureSpec 类,它是一个32位的 int 值,高两位为测量模式,低30位为测量大小,使用位运算提高并优化效率。

重写
onMeasure()
后,最终要做的是把测量后的宽高值作为参数设置给
setMeasureDimension()
方法。

[代码]java代码:

?
即,如果不重写
onMeasure()
方法,系统则会不知道该默认多大尺寸,就会默认填充整个父布局,所以,重写
onMeasure()
方法的目的,就是为了能够给 View 一个 wrap_content 属性下的默认大小。

View 的绘制

onDraw()
中的参数,就是 Canvas 对象,使用该对象进行绘图,而在其他地方,则需要 new 出该对象:

[代码]java代码:

?
传进去的 bitmap 是与这个 bitmap 创建的 Canvas 画布紧密联系的,这个过程称为装载画布。该 bitmap 用来存储所有绘制在 Canvas 上的像素信息。所有的 Canvas.drawXXX 方法都发生在这个 bitmap 上。

[代码]java代码:

?
通过 mCanvas 将绘制效果作用在了 bitmap2 上,再刷新 View 的时候,就会发现通过
onDraw()
方法画出来的 bitmap2 已经改变,因为 bitmap2 承载了在 mCanvas 上所进行的绘图操作。我们没有将图形直接绘制在
onDraw()
方法制定的那块画布上,而是通过改变 bitmap,让 View 重绘,从而显示改变之后的 bitmap。

ViewGroup 的测量

当 ViewGroup 的大小为 wrap_content 时,ViewGroup 需要对子 View 进行遍历,以便获得所有子 View 大小从而决定自己的大小,即调用子 View 的 Measure 方法来获得每一个子 View 的测量结果。

子 View 测量完毕后,ViewGroup 执行 Layout 过程时,同样是遍历调用子 View 的 Layout 方法,并指定其具体显示的位置,从而来决定其布局位置。

自定义 View

[代码]java代码:

?
在 attrs.xml 中通过使用
<declar-styleable>
标签声明使用了自定义属性,使用如下代码获得在布局文件中自定义的那些属性

[代码]java代码:

?

自定义 ViewGroup

重写
onMeasure()
来对子 View 进行测量,重写
onLayout()
确定子 View 位置,重写
onTouchEvent()
增加响应事件。

实例需求:自定义 ViewGroup 实现类似 ScrollView 上下滑动,同时增加粘性效果。即,当一个子 View 向上滑动大于一定距离后,松开将自动上滑,显示下一个子 View,否则回到原始位置。

步骤一:先实现类似 ScrollView 功能:

[代码]java代码:

?

步骤二:再对子 View 进行放置位置设定,让每个子 View 都显示完整的一屏。所以,本例中ViewGroup 的高度就是子 View 的个数乘以屏幕高度,然后遍历设定每个子 View 放置的位置

[代码]java代码:

?

步骤三:

[代码]java代码:

?

事件拦截机制



点击 View 的 log:

[代码]java代码:

?
所以事件传递顺序是:先执行
dispatchTouchEvent()
然后是
onInterceptTouchEvent()
。返回值:True,拦截,不继续;False,不拦截,继续流程。初始返回是 false。

事件处理顺序是:
onTouchEvent()
。返回值:True,处理了,不审核;False,给上级处理。初始返回是 false。

即:

分发、拦截:如果某个 ViewGroup 直接使用
dispatchTouchEvent()
返回了 true ,则分发拦截结束,不再向其子 View 传递,则,直接执行该 ViewGroup 的
onTouchEvent()
,然后继续向上处理对应 ViewGroup 的
onTouchEvent()


处理:如果某个 View 直接在
onTouchEvent()
中返回了 true。则上级不再执行
onTouchEvent()
。所有的处理在此结束。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: