自定义View和ViewGroup

自定义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的使用效果。

坚持原创技术分享,您的支持将鼓励我继续创作!