最近与朋友聊天,朋友吐槽说去面试的时候自定义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 中长按给了用户一个震动的反馈。