安卓Android原理Android UI

[Android技术专题]自定义View从入门到上天

2016-08-15  本文已影响5138人  张明云

一、前言

标题起得屌了点,文章只能给大家带来理论知识,能不能上天还是得各位亲自实践。文中涉及到很多自己的理解,能力有限,有问题的地方还请指正,文中的参考资料都是精心筛选的,非常值得阅读。

很多人把自定义View想得复杂了,以为有多高深,主要还是没有实践过,没有足够的自信;但也有很多人把自定义View想得简单了,以为摸清View的几个关键回调、知道自定义属性和Android的消息分发机制就算是老司机了,其实对于自定义View来讲,设计、排版、效率都是很费脑筋的,我在github上到现在都没发现一个像样的图文混排自定义View。

常见的Android自定义View主要有两种类型:

按照上面这种方式分只是便于理解,很多时候有些控件既有组合,又需要复写所继承类的回调方法。

二、自定义View的价值

三、有必要了解的核心知识点

View、SurfaceView、TextureView的区别

View的三大核心方法onMeasure、onLayout、onDraw

自定义属性

对于自定义View的一些属性设置,除了可以在自定义View中提供公开接口外,还可以通过自定义属性,在对自定义View布局时就指定,这样可以简化用户使用控件的复杂度,实现自定义属性的步骤如下:

对自定义属性的解析需要注意两点:

1.TypedArray使用完成后一定要调用其recycle方法,否则会有内存泄露的问题;

2.如果自定义View在一个单独的module中(不属于主工程),对attr的获取不能使用switch-case语句,要用if...else,具体原因之前有介绍过,详见:在Android library中不能使用switch-case语句访问资源ID的原因分析及解决方案

完成自定义属性的定义后,就可以在布局自定义View的过程中使用自定义属性了,具体步骤如下:

双缓冲

在移动设备中很容易出现效率问题,对于效率问题的处理,主要方法是时间换空间或者空间换时间;自定义View可能存在显示的效率问题,可以通过双缓冲来解决这个问题,双缓冲就是用空间换时间的典型例子,同一个View在内存中创建了两份同样大小的内存,一份用于绘制,一份用于显示,绘制是绘制在Bitmap上,显示就是将这张bitmap显示在画布上。

硬件加速

在Android设备中,硬件加速默认是开启的,有些应用出于内存占用(开启硬件加速会占用更多的内存)和应用特征的考虑(没什么动画,基本没有涉及到需要GPU的操作),会在AndroidManifest.xml中关掉硬件加速,这会导致自定义View时,canvas的某些方法不能正常使用,为了让自定义View达到更好的表现效果,建议不要关掉有用到自定义View界面的硬件加速(因为在View层面只能关闭硬件加速,无法开启硬件加速,所以只能控制Activity和Window层面的硬件加速)。

图文混排:

涉及到图文混排的自定义View,一定要将排版和显示这两件事情分开,因为排版耗时但不涉及到UI的更新,可以在线程中处理,但显示必须要更新UI,所以在onDraw方法里面尽量不要做耗时和逻辑处理,只纯粹做显示操作。对于排版可以考虑异步,或者先完成排版,后续只需要直接显示即可,这得具体问题具体分析。

同时显示也有技巧,为了节省内存,可以考虑做缓存,一个控件可能不只一页内容,可以在内存中缓存当前页和当前页的前、后两页,当滑动时,始终按照这种策略更新缓存内容就可以了,这样既达到了节省内存、又提高效率的目的。

getHistorySize

对于有涉及到触摸操作的自定义View(比如手写控件),是在onTouchEvent方法中接收触摸消息的,但限于Android系统和设备本身的情况,底层上报的点信息不一定能够实时通过MotionEvent回调到上层,底层1秒钟可能传了几百个点,但onTouchEvent方法中接收到的可能只有几十个点,如果需要更为平滑地点信息,可以借助MotionEvent的getHistorySize方法获取底层上报的更多点信息,关于getHistorySize的解释,请参见参考资料中对平滑手写签名效果的介绍。

SpannableString

使用过SpannableString的都知道,可以通过它将同一串字符中的不同文字做不同的处理,比如某些文字的颜色、字体、背景色、大小等有变化,都可以通过它来设置,熟练掌握SpannableString对于灵活自定义View会有很大地帮助。

四、参考资料

五、优质开源项目

六、忠告

千万别一言不合就自定义,能够用Android基础控件解决的问题就尽量用基础控件,其次是用基础控件的组合,如果是确实有必要自定义才考虑自定义。自定义的控件既需要耗费较长的开发时间,又不一定能保证有基础控件那么高的效率(基础控件都是谷歌优化过了的)。

更多原创文章和优质资源请关注公众号:

open_dev
上一篇下一篇

猜你喜欢

热点阅读