分类与流程
-
View的绘制流程
自定义View绘制函数调用序列:
-
分类
- 自定义View
在没有现成的View,需要自己实现的时候,就使用自定义View,一般继承自View,SurfaceView或其他的View,不包含子View。 - 自定义ViewGroup
自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或各种Layout,包含有子View。
-
重要函数
-
构造函数
public void SloopView(Context context) {}
public void SloopView(Context context, AttributeSet attrs) {}
public void SloopView(Context context, AttributeSet attrs, int defStyleAttr) {}
public void SloopView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {}
有三个参数的构造函数中第三个参数是默认的Style,这里的默认的Style是指它在当前Application或Activity所用的Theme中的默认Style,且只有在明确调用的时候才会生效,以系统中的ImageButton为例说明:
public ImageButton(Context context, AttributeSet attrs) {
//调用了三个参数的构造函数,明确指定第三个参数
this(context, attrs, com.android.internal.R.attr.imageButtonStyle);
}
public ImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
//此处调了四个参数的构造函数,无视即可
this(context, attrs, defStyleAttr, 0);
}
注意:即使你在View中使用了Style这个属性也不会调用三个参数的构造函数,所调用的依旧是两个参数的构造函数。
由于三个参数的构造函数第三个参数一般不用,暂不考虑,第三个参数的具体用法会在以后用到的时候详细介绍。
排除了两个之后,只剩下一个参数和两个参数的构造函数,他们的详情如下:
//一般在直接New一个View的时候调用。
public void SloopView(Context context) {}
//一般在layout文件中使用的时候会调用,关于它的所有属性(包括自定义属性)都会包含在attrs中传递进来。
public void SloopView(Context context, AttributeSet attrs) {}
-
onMeasure() 测量View大小
View的大小不仅由自身所决定,同时也会受到父控件的影响,为了我们的控件能更好的适应各种情况,一般会自己进行测量。
从onMeasure的两个参数中取出宽高的相关数据:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthsize MeasureSpec.getSize(widthMeasureSpec); //取出宽度的确切数值
int widthmode MeasureSpec.getMode(widthMeasureSpec); //取出宽度的测量模式
int heightsize MeasureSpec.getSize(heightMeasureSpec); //取出高度的确切数值
int heightmode MeasureSpec.getMode(heightMeasureSpec); //取出高度的测量模式
}
从上面可以看出 onMeasure 函数中有 widthMeasureSpec 和 heightMeasureSpec 这两个 int 类型的参数, 毫无疑问他们是和宽高相关的, 但它们其实不是宽和高, 而是由宽、高和各自方向上对应的测量模式来合成的一个值:
测量模式一共有三种, 被定义在 Android 中的 View 类的一个内部类View.MeasureSpec中:
|模式 |二进制数值| 描述
|---------|-----------|------
|UNSPECIFIED|00| 默认值,父控件没有给子view任何限制,子View可以设置为任意大小。
|EXACTLY |01| 表示父控件已经确切的指定了子View的大小。
|AT_MOST |10| 表示子View具体大小没有尺寸限制,但是存在上限,上限一般为父View大小。
在int类型的32位二进制位中,31-30这两位表示测量模式,29~0这三十位表示宽和高的实际值,实际上如下:
UNSPECIFIED | 00 | 000000000000000000001111011000
注意:
如果对View的宽高进行修改了,不要调用 super.onMeasure( widthMeasureSpec, heightMeasureSpec); **要调用 setMeasuredDimension( widthsize, heightsize); **
-
onSizeChanged() 确定View大小
View的大小不仅由View本身控制,而且受父控件的影响,所以我们在确定View大小的时候最好使用系统提供的onSizeChanged回调函数。
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
-
onLaytout() 确定子View布局位置
名称 | 说明 | 对应的函数 |
---|---|---|
l | View左侧距父View左侧的距离 | getLeft(); |
t | View顶部距父View顶部的距离 | getTop(); |
r | View右侧距父View左侧的距离 | getRight(); |
b | View底部距父View顶部的距离 | getBottom(); |
-
onDraw() 绘制