Android View的工作原理(三)自定义View
自定义View是一个综合的技术体系,它涉及到的内容非常广泛,主要包括View的层次结构、事件分发机制、滑动冲突和View的工作原理等待。要想灵活地掌握这门“技术活”,基础知识是不可缺少的,因此在这之前花了很长时间总结View的事件体系和View的工作原理。
假如你对这些基础知识理解得还不是很透彻,或者有一些知识点的遗忘,欢迎阅读我在这之前总结的相关文章。
Android View的事件体系(一)基础知识
Android View的事件体系(二)View的滑动
Android View的事件体系(三)弹性滑动
Android View的事件体系(四)事件分发机制(有空继续撸源码)
Android View的事件体系(五)滑动冲突
View的工作原理(一)基本概念
View的工作原理(二)View的工作流程
一、自定义View的分类
注:分类没有一个统一的标准,以下的分类方式只是为了方便理解。
1、直接继承View并重写onDraw方法
这种方法主要用于实现一些不规则的效果,例如自定义一个颜色会随进度变化的进度条控件,显然需要我们自己来实现绘制方式,即需要重写onDraw方法。这种方式需要自己支持属性wrap_content,并且还要考虑到自身的padding属性。
2、继承ViewGroup派生出特殊的布局
这种方法主要用来实现自定义的布局,假如我们需要一个有别于LinearLayout、RelativeLayout等系统布局的新布局,可以采用这种方式实现。采用这种方式不仅需要正确地处理自身的测量和布局过程,而且还要处理好所有子元素的测量和布局过程,所以还是比较复杂的。
3、继承系统已有的控件(例如TextView)
这种方法是比较常见的,一般是用于扩展现有系统控件(例如TextView)的功能,这种方法相对来说比较容易实现,因为很多细节不需要自己考虑。
4、继承系统已有的ViewGroup(例如LinearLayout)
这种方法也比较常见,当你需要扩展某种已有布局(例如LinearLayout)的功能,例如横向布局、子元素自动换行的LinearLayout,这种方法不需要自己处理ViewGroup的测量和布局这两个过程。
开始自定义View之前,需要找到一种代价最小、最高效的方式来实现它显得至关重要,因为一个正确的实现方式可能会让开发工作变得轻松许多。
二、自定义View注意事项
自定义View是一个考验耐心的工作,因为在这个过程中可能会出现各种各样的问题,例如 View无法正常使用、导致内存泄漏 等等。为了帮助我们防患于未然,接下来会介绍一些具体的注意事项。
1、让View支持wrap_content
直接继承View或者ViewGroup的控件,如果不在onMeasure方法里面处理wrap_content,那么在布局文件中使用wrap_content会出现match_parent的效果。具体处理方法在Android View的工作原理(二)View的工作流程已经介绍过。
2、如果有必要,让View支持padding属性
直接继续View的控件如果不在draw方法中处理padding,那么布局文件中的padding属性将不起作用。
直接继承ViewGroup的控件,在onMeasure和onLayout中也需要考虑padding属性和子元素的margin对它造成的影响,否则将导致padding和子元素的margin失效。
3、尽量不要在自定义View的时候使用Handler
一方面是因为View本身就提供了post系列的方法,完全可以替代Handler的作用;另一方面是因为使用Handler容易导致内存泄漏。
4、View中如果有线程或者动画,需要及时停止
设想一个场景,我们的View持有某个Activity的引用,当Activity被销毁或者View被移除出UI界面,这个时候我们应该停止View上的线程和动画,否则可能会造成内存泄漏。
至于什么时候开始停止线程和动画,也许View#onDetachedFromWindow方法会是一个很好的时机,因为当View从Window上分离(detached)的时候(例如拥有View的Activity退出或者View被remove),View#onDetachedFromWindow方法会被调用。同时,当View变得不可见时我们也要停止线程和动画。
5、View当中有滑动嵌套的情形时,需要处理好滑动冲突
三、自定义View示例
介于自定义View种类较多、且每一类所占篇幅比较长,如果都放在此处未免显得冗长,因此决定根据种类划分,单独介绍这些实例。
Android自定义View示例(一)直接继承View
Android自定义View示例(二)直接继承ViewGroup
参考
《Android开发艺术探索》