第三章:Android控件架构与自定义控件详解
Android控件架构

上图为View
树结构,Activity
中使用的findViewById()
方法,就是在控件树中以树的深度优先遍历来查找对应的元素.每棵树的顶部都有一个ViewParent
对象,是整棵树的控制核心,所有的交互事件都由它统一调度和发配,从而可以对整个视图进行整体的控制.
Activity
中使用setContentView
设置布局之后布局内容才能显示到屏幕上,setContentView
所做的工作如下:

上图是UI界面的架构图,每个Activity
都包含一个Window
对象,在Android
中通常有PhoneWindow
来实现,PhoneWindow
将一个DecorView
设置为整个应用窗口的根View
.DecorView
将要显示的内容呈现在PhoneWindow
上,这里所有的View
的监听事件都通过WindowManagerService
来进行接收.而在显示上,把屏幕分成两部分,TitleView
和ContentView
.
在代码中,onCreate
调用setContentView
方法后,ActivityManagerService
会回调onResume
方法,此时系统才会把整个DecorView
添加到PhoneWindow
中,并让其显示出来,完成最终的界面的绘制.
View
的测量
Android
系统为测量提供了一个功能强大的类-MeasureSpec
,通过它可以获取测量的模式与测量的数据.
MeasureSpec
是一个32
位的int
值,其中高两位表示的是测量的模式,低30
位表示的是测量的大小,使用位运算是为了提高并优化效率.
测量的模式:

View
默认的onMeasure
测量模式只支持EXACTLY
,如果要支持wrap_content
,则必须重写onMeasure方法.
onMeasure
设置大小用setMeasuredDimension(int width , int height)
来设置控件的大小.
获取MeasureSpec
的数据
int size = MeasureSpec.getSize(measureSpec);
int mode = MeasureSpec.getMode(measutrSpec);
处理wrap_content
的模板(onMeasure()
中);
int result = 0 ;
int specSize = MeasureSpec.getSize(measureSpec);
int specMode = MeasureSpec.getMode(measureSpec);
if(specMode == MeasureSpec.EXACTLY){
resulr = specSize ;
} else {
result = 200 ;
if(specMode == MeasureSpac.AT_MOST){
resutl = Marh.min(result , specSize) ;
}
}
View
的绘制:
将Canvas
的绘制内容显示到Bitmap上
Canvas canvas = new Canvas(bitmap) ;
ViewGroup
的测量与放置子View
当大小为wrap_content
的时候,ViewGroup
的大小为能容纳下所有子view
的最小值,即需要对子View
进行遍历,子View
位置的放置也是需要对子View
进行遍历.然后调用layout
来放置子View
.ViewGroup
不会调用onDraw
方法来绘制,除非设置背景色,但是ViewGroup
会调用dispatchDraw()
方法来绘制其子View,其过程同样是遍历所有子View
,调用子View
的绘制方法来完成绘制工作.
自定义View
:
常用的重要方法:
- onFinishInflate() : 从XML加载组件后的回调
- onSizeChaged() : 组件改变大小时回调
- onMeasure() : 回调该方法进行测量
- onlayout() : 回调该方法来确定显示的位置
- onTouchEvent() : 监听到触摸事件时回调
实现自定义的方法

首先介绍对现有控件进行扩展的方法
一个简单的例子(效果图):

实现原理分析:从图中可以看出是继承自TextView,在绘制文字之前绘制两个背景,一个尺寸为控件的尺寸,一个对控件的上下左右都存在偏移
稍复杂一点的TextView
,闪动的TextView
效果图

组合现有的组件实现新的组件
仿电商项目的顶部栏
效果图:

剩下的下次再补~