自定义View
在自定义View时,通常需要重写onDraw()方法绘制View的显示内容;如果需要使用wrap_content属性,还需要重写onMeasure()方法进行测量;另外,还可以在attrs.xml文件中为View自定义属性。
在View中通常用到的回调方法有:
onFinishInflate()
从XML文件中加载控件后调用;onSizeChanged()
控件大小改变时调用;onMeasure()
测量控件大小时调用onLayout()
确定控件显示位置时调用onDraw()
绘制控件时调用;onTouchEvent()
监听触摸事件时调用;
在自定义View的时候,只需要重写特点条件的回调方法。
通常情况下,自定义View有三种方式:对现有View进行扩展、创建复合View、自定义新的View。
对现有View进行扩展
这种方式是在原生View的基础上进行扩展,比如修改显示的效果、增加新的功能等。
通常可以在onDraw()方法中,对原生View进行扩展。
创建复合View
这种方式通常需要继承一个合适的ViewGroup,再给它添加指定功能的控件,从而组合成新的复合View。
对于复合View,一般会给它指定一些自定义属性,让其具有更强的扩展性。
自定义新的View
当原生View无法满足需求时,可以通过继承View,自定义一个新的View。
自定义新的View,最重要的是绘制View和实现交互。绘制逻辑需要重写onDraw()和onMeasure()方法,交互逻辑需要重写onTouchEvent()等控制触控事件的方法。还可以像实现复合View那样,为新的View配置自定义属性,丰富自定义View的可定制性。
自定义ViewGroup
ViewGroup用于管理一组子View,将子View放到合适的位置,并为其添加响应事件。
自定义ViewGroup通常需要重写onMeasure()方法对子View进行测量,重写onLayout()方法确定子View的位置,重写onTouchEvent()方法为子View设置响应事件。
自定义控件的注意事项
- 让View支持wrap_content
当直接继承View或ViewGroup自定义控件时,需要在onMeasure()方法中对wrap_content做特殊处理,否则,当外界在布局中使用wrap_content时无法达到预期效果。
- 如有必要,让View支持padding和margin
直接继承View自定义控件如果不在onDraw()方法中处理padding属性,那么,其padding属性是无法起作用的;另外,直接继承ViewGroup的自定义控件需要在onMeasure()和onLayout()方法中考虑padding属性和子View的margin属性对其造成的影响,否则,其padding属性和子View的margin属性将会失效。
- 尽量不要在View中使用Handler
View内部提供了post系列方法,基本上可以代替Handler。
- View中如果有线程或动画,需要及时停止
当View所在的Activity退出或者当前View被remove时,可以调用View.onDetachedFromWindow()方法中停止线程或动画;同时,当View不可见时,也需要停止线程和动画。如果不及时处理这些问题,可能会造成内存泄露。
- View带有滑动嵌套时,需要处理好滑动冲突
如果自定View中有滑动嵌套的情形,需要合理地处理滑动冲突,否则,会严重影响View的使用效果。