Android — 自定义View(一)之基础知识
前言
记得之前写过一篇自定义View的文章,当时也是尝尝鲜。今天看到一篇自定义View系列文章,也是蛮新的,决定要认认真真的系统学习一遍。原文地址:http://www.gcssloop.com/customview/CustomViewIndex/ 当然,系列中有些东西我觉得很没必要,我想学最实用的知识。(可能我的看法有些片面)还有文章中讲的有些我不明白的地方,我在看看别的博客在加上自己的理解写了这篇博客。这篇文章再详细记录一下学习中非常重要的知识点和要注意的东西。整体目录如下:
- View坐标系
- 自定义View绘制流程概述
- 总结流程关键字以及作用
那准备好了吗?
View 坐标系
首先要明确的是:Android中的坐标系统是以左上角为坐标原点,向右是X轴正方向,向下是Y轴正方向。View的坐标系统是相对于父控件而言的。
View 获取自身宽高:
- getHeight() 获取View自身高度
- getWidth() 获取View自身宽度
View 自身坐标:
- getTop() 获取View自身顶边到其父布局顶边的距离
- getLeft() 获取View自身左边到其父布局左边的距离
- getRight() 获取View自身右边到其父布局左边的距离
- getBottom() 获取View自身底边到其父布局顶边的距离
MotionEvent提供的方法:
- getX() 获取点击事件距离控件左边的距离,即视图坐标
- getY() 获取点击事件距离控件顶边的距离,即视图坐标
- getRawX() 获取点击事件距离整个屏幕左边距离,即绝对坐标
- getRawY() 获取点击事件距离整个屏幕顶边的距离,即绝对坐标
说了那么多,还是来一图胜千言吧。
自定义View绘制流程
盗一张图:
几个非常重要的函数:
构造函数
构造函数是View的入口,可以用于初始化一些内容,和获取自定义属性。View的构造函数有四种重载,而有四个参数的构造函数在API21的时候才添加上,暂不考虑。而有三个参数的构造方法中第三个参数是默认的Style,这里默认的Style是指它在当前Application或Activity所用Theme中的默认Style,且只有在明确调用的时候才会生效。
需要注意的是,即使你在View中使用了Style这个属性也不会调用三个参数的构造方法,所以调用的依旧是两个参数的构造方法。
调用一个参数的构造方法:
1CustomView view = new CustomView(this);调用两个参数的构造方法:
1234//在layout文件中 - 格式为: 包名.View名<top.omooo.CustomViewandroid:layout_width"wrap_content"android:layout_height"wrap_content"/>onMeasure() 测量View大小
View的大小不仅由自身所决定,同时也会受到父控件的影响,为了我们的控件能更好的适应各种情况,一般我们会自己进行测量。
1234567
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //获取宽度的确切数值 int widthSize = MeasureSpec.getSize(widthMeasureSpec); //获取宽度的测量模式 int widthMode = MeasureSpec.getMode(widthMeasureSpec); }
onMeasure()函数中有两个参数,很显然它们是和宽高相关的,**但是实际上它们不是宽和高** ,而是由宽高和各自方向上对应的测量模式来合成的一个值。
测量模式一共有三种,被定义在Android中的View类的一个内部类View.MeasureSpec中。
注意,如果对View的宽高进行修改了,不要调用super.onMeasure();而是调用setMeasuredDimension() 这个函数。
onSizeChanged() 确定View的大小
为什么View的大小测量完了,还要再次确定View的大小呢?这是因为View的大小不仅由View本身控制,而且还受父控件的影响。所以我们在确定View的大小的时候最好使用系统提供的onSizeChanged()回调函数。
12345678910
/*** @param w View最终的宽* @param h View最终的高* @param oldw 上一次宽* @param oldh 上一次高*/ protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); }
onLayout() 确定子View布局位置
在自定义ViewGroup中的时候,会用它确定子View的位置。onLayout() 一般是循环取出子View,然后计算各个子View的坐标值,然后用以下函数设置子View的位置。
123456
/*** @param l getLeft()* @param t getTop()* @param r getRight()* @param b getBottom()*/
@Override
public void layout(int l, int t, int r, int b) {
super.layout(l, t, r, b);
}
onDraw() 绘制内容
是实际绘制的部分,使用的是Canvas绘图。
1234
protected void onDraw(Canvas canvas) { super.onDraw(canvas);}
另外
自定义View之后,一般会对外暴露一些接口,用于控制View的状态或监听View的变化等等。
总结
步骤 | 关键字 | 作用 |
---|---|---|
1 | 构造函数 | View初始化 |
2 | onMeasure() | 测量View大小 |
3 | onSizeChanged() | 确定View大小 |
4 | onLayout() | 确定子View布局 |
5 | onDraw() | 实际绘制内容 |
6 | 提供接口 | 控制View或监听View状态 |