参考文章:
GcsSloop
教你搞定Android自定义View
frank909
一.自定义View分类
1.自定义ViewGroup
自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或各种Layout,包含有子View。
2.自定义View
在没有现成的View,需要自己实现的时候,就使用自定义View,一般继承自View,SurfaceView或其他的View,不包含子View。
二、几个重要的方法
1、构造函数
构造函数是View的入口,可以初始化一些数据和获取自定义的属性
View构造函数有四个重载方法:
有四个参数的构造函数在API21才引入的,暂不考虑
有三个参数的构造函数中第三个参数是默认的Style,这里的默认的Style是指它在当前Application或Activity所用的Theme中的默认Style,且只有在明确调用的时候才会生效,以系统中的ImageButton为例说明:
注意:即使你在View中使用了Style这个属性也不会调用三个参数的构造函数,所调用的依旧是两个参数的构造函数。
还剩下两个构造函数:
以下方法调用的是一个参数的构造函数:
MyCustomView myView=new MyCustomView(this)
以下方法调用的是两个参数的构造函数:
<com.sloop.study.MyCustomView
android:layout_width"wrap_content"
android:layout_height"wrap_content"/>
2.测量View大小(onMeasure)
View的大小不仅由自身所决定,同时也会受到父控件的影响,为了我们的控件能更好的适应各种情况,一般会自己进行测量。
测量View大小使用的是onMeasure函数,我们可以从onMeasure的两个参数中取出宽高的相关数据:
从上面可以看出 onMeasure 函数中有 widthMeasureSpec 和 heightMeasureSpec 这两个 int 类型的参数, 毫无疑问他们是和宽高相关的, 但它们其实不是宽和高, 而是由宽、高和各自方向上对应的测量模式来合成的一个值:
测量模式一共有三种, 被定义在 Android 中的 View 类的一个内部类View.MeasureSpec中:
1、UNSPECIFIED:这个模式下,View想多大就多大,通常在绘制自定义View时才会使用
2、EXACTLY
就是 精确值模式
当我们的View的layout_width 或者 layout_height属性设置为具体的数值(例: android:layout_width = “100dp”)
或者指定为 “match_parent” 时(这时候系统会自动分配为父布局的大小)
就是使用的这个模式3、AT_MOST
就是 最大值模式
当我们的View的layout_width 或者 layout_height属性设置为 “wrap_content” 时
也就是控件的大小随着子控件或者内容的变化而变化,这时候只要控件的尺寸不超过父布局允许的最大尺寸即可在实际运用之中只需要记住有三种模式,用 MeasureSpec 的 getSize是获取数值, getMode是获取模式即可
注意:
如果对View的宽高进行修改了,不要调用super.onMeasure(widthMeasureSpec,heightMeasureSpec);
要用setMeasuredDimension(widthsize,heightsize);
3、确定子View布局位置(onLayout)
确定布局的函数是onLayout,它用于确定子View的位置,在自定义ViewGroup中会用到,他调用的是子View的layout函数
在自定义ViewGroup中,onLayout一般是循环取出子View,然后经过计算得出各个子View位置的坐标值,然后用以下函数设置子View位置。
child.layout(l, t, r, b);
4、绘制内容(onDraw)
onDraw是实际绘制的部分,也就是我们真正关心的部分,使用的是Canvas绘图。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}