一些基础知识
View简介
View就是显示在屏幕上的各种视图
View类是Android各种组件的基类
视图View的分类
- 单一视图(例如:TextView、Button)
- 视图组:由多个单一视图组成的ViewGroup(例如LinearLayout、RelativeLayout)
View的构造函数一共有四个
1
2//在Java代码中新建一个实例,则调用这个构造函数
public View(Context context)1
2//如果view是在xml文件中声明的,则调用这个构造函数
public View(Context context, @Nullable AttributeSet attrs)1
2//这个不会自动调用,一般来说这个是在第二个构造函数中主动调用(在view有style属性时)
public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr)1
2
3
4
5/**
* api21之后才使用
* 一般在第二个构造函数中主动调用
*/
public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)
View的视图结构
位置的获取
- view的位置是通过
view.get×××()
获取的 - MotionEvent中的位置获取
- view的位置是通过
Android坐标系
角度:在默认的屏幕坐标系中角度增大方向为顺时针
android中的颜色
颜色模式 解释 ARGB8888 四通道高精度(共32位),每个通道8位 ARGB4444 四通道低精度(共16位) RGB565 Android屏幕默认的模式(16位) Alpha8 仅有透明通道(8位) 类型 解释 取值范围(0x00-0xff) A(Alpha) 透明度 透明-不透明 R(Red) 红色 无色-红色 G(Green) 绿色 无色-绿色 B(Blue) 蓝色 无色-蓝色
View的Measure过程
本过程作用:测量View的宽/高
ViewGroup.LayoutParams
类:用来传递宽/高的值的类ViewGroup的子类有相应的
ViewGroup.LayoutParams
子类,例如与RelativeLayoutParams
对应的便是RelativeLayoutParams
具体作用是用来记录视图的
height
和width
等布局参数MeasureSpecs类:用来记录父布局对子视图测量要求的类
测量规格(MeasureSpec) = 测量模式(mode)+ 测量大小(size)
测量规格一共32位(int),其中测量模式占MeasureSpec的高2位,测量大小占MeasureSpec的低30位
测量模式
MeasureSpec的值的计算
子View的MeasureSpec值的计算是根据子View的LayoutParams和父容器的MeasureSpec值计算得来的。具体的逻辑都封装在getChildMeasureSpec()里
ps:顶级View(DecorView)的测量规格MeasureSpec计算逻辑:取决于自身布局参数和窗口尺寸
measure过程详解
measure过程根据view的类型分为单一View的测量
和ViewGroup的
测量
测量流程
这里重点讲一下getDefaultSize()方法,其他的请自行查阅源代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29/**
* size:提供的默认大小
* measureSpec:宽/高的测量规格(含模式 & 测量大小)
*/
public static int getDefaultSize(int size, int measureSpec) {
// 默认大小
int result = size;
// 获取宽/高测量规格的模式 & 测量大小
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
// 模式为UNSPECIFIED时,使用提供的默认大小 = 参数Size
case MeasureSpec.UNSPECIFIED:
result = size;
break;
// 模式为AT_MOST,EXACTLY时,使用View测量后的宽/高值 = measureSpec中的Size
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
// 返回View的宽/高值
return result;
}在这里的size是默认数值,那这个默认数值是怎么来的呢,先看看
onMeasure()
中,调用getDefaultSize()
方法:getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec)
。这里就可以看出传进去的默认的大小是getSuggestedMinimumWidth()
1
2
3protected int getSuggestedMinimumWidth() {
return (mBackground == null) ? mMinWidth : max(mMinWidth,mBackground.getMinimumWidth());
}从这儿看,如果View没有设置背景,那么View的宽度就是
mMinwidth
View的layout过程
流程图
源码分析
1 | /** |
小细节
getWidth()(getHeight())和getMeasuredWidth()(getMeasuredHeight())有什么区别
- getWidth()(getHeight()):获取View的最终的宽/高
- 取值在measure过程
- 取值方法:setMeasuredDimension()
- getMeasuredWidth()(getMeasuredHeight()):获取的View的测量的宽/高
- 取值在layout过程
- 取值方法:layout中传递四个参数之间的运算
1 | // 获得View测量的宽 / 高 |
ps:一般情况下(屏幕可包裹内容,无人为设置),这两个获取的值是相等的,但是也可以人为强行设置
1 |
|
View的Draw过程
流程图
绘制流程
- 绘制view背景
- 绘制view内容
- 绘制子View
- 绘制装饰(渐变框,滑动条等等)
源码分析
1 | /** |