最近与朋友聊天,朋友吐槽说去面试的时候自定义View方面的问题问了好久,我说不是很正常吗,最基本的。 把好久之前学Android 自定义View整理了一下。顺便写了一个demo。
稍微总结了一下四个点:
- 布局与绘制、基本回调方法、熟练使用
View的api- 事件分发
- 动画
- 细节
布局与绘制、基本回调、熟练使用View的api
需要做到的是measure、layout、draw方法的熟练掌握,这就需要掌握View的绘制流程逻辑。熟悉常用的回调方法。熟悉常用View的api。
measure
用来测量View的大小,流程是DecorView->ViewGroup->View。自定义ViewGroup的时候需要确保所有可见View调用了measure。里面有一些细节知识,比如注意View的Padding 值。
有两个关键的地方需要掌握:DecorView的测量和普通View的测量。
DecorView(根View)的测量,可以参考ViewRootImpl.measureHierarchy和ViewRootImpl.getRootMeasureSpec。可以看到getRootMeasureSpec中计算DecorView高度是根据DecorView设置的大小和window 的大小。这里是判断DecorView设置大小之后才计算的,与测量普通的View(非DecorView)是不一样的。
|
|
普通View的测量,可以参考ViewGroup.getChildMeasureSpec。View的大小主要根据ViewGroup的MeasureSpec和设置的大小决定的。这里就不贴代码了。

layout过程
layout用来确定View(主要是在自定义ViewGroup时的子View)的位置,流程也是DecorView->ViewGroup->View。可以查看demo 中的onLayout用来设置各个子View的位置。
draw过程
重点需要知道绘制的顺序。
- Draw the background
- If necessary, save the canvas’ layers to prepare for fading
- Draw view’s content
- Draw children
- If necessary, draw the fading edges and restore layers
- Draw decorations (scrollbars for instance)
常用的回调方法
onAttachedToWindow
onDetachedFromWindow
onFinishInflate
…
数量掌握每一个回调里面应该处理什么内容。
常用View的api
scrollBy
scrollTo
invalidate
requestLayout
…
还有demo 中的bringToFront。对View的api熟悉可以在很多时候为自己节约很多时间。
事件分发
基本的事件分发的流程是Activity->ViewGroup->View。伪代码如下:
|
|
处理事件分发时一个需要注意的是滑动冲突的问题,这里就需要熟练地掌握事件分发的流程。可以参考Demo 中的一个滑动冲突问题,DragScrollView中是一个DragView,当长按选中一个item 的时候就会拦截DragScrollView的滚动事件,解决的办法是在DragView的dispatchTouchEvent调用getParent().requestDisallowInterceptTouchEvent(true)拦截了DragScrollView的事件。
动画
动画目前有两种主要的实现:View动画和属性动画(5.0以后的过渡动画这里没有考虑)。需要熟练的掌握不同动画的原理,在不同的需求中可以做出比较好的选择。demo 中使用到的是View动画。
细节
主要是交互、适配等等。
save && restore
主要关注的是onSaveInstanceState和onRestoreInstanceState。流程是:Activity->ViewGroup->View(这里去掉了Fragment)
在demo 中,用户排序完一个顺序以后,后台处理其他事情然后Activity被回收了,再回来发现需要重新排序,这样肯定不好。可以参考demo(demo 里面处理的是Activity)。
交互
android 中的长按一般代表什么操作;双击应该怎么处理;是向左还是向右滑动等等。比如demo 中长按给了用户一个震动的反馈。