面试问题
- onMeasure onLayout onDraw的作用
- 自定义View和自定义ViewGroup的区别
- getMeasureWidth和getWidth的区别
- getLeft getRight getWidth表示的意义
- MeasureSpec是什么
- 如何优化自定义View
- 自定义view效率高于xml定义吗
- Draw的基本流程
- setWillNotDraw的作用
- invalidate()、postInvalidate()、requestLayout()的区别
onMeasure onLayout onDraw的作用
- onMeasure:用来计算控件的尺寸,告诉父控件此控件需要的尺寸。
- onLayout:父容器的onLayout()调用子类的layout()来确定子view在viewGroup中的位置。
- onDraw:自定义view的关键方法,用于绘制界面,可以重写此方法以绘制自定义View。
自定义View和自定义ViewGroup的区别
- ViewGroup是一个容器,而这个容器是继承与View。
- ViewGroup是一个基类,并且是Layout和一些View组件的基类。
getMeasureWidth和getWidth的区别
- getMeasureWidth()在走完onMeasure()方法之后有值
- getWidth()在layout()之后有值,是布局完成之后的确切值
- getMeasureWidth()在onMeasure()之后调用
- getWidth()在layout()之后调用
- getMeasureWidth()是view的一个测量大小
- getWidth()是view被父布局摆放的大小
getLeft getRight getWidth表示的意义
getWidth()的值就是getRight()-getLeft()的值。
MeasureSpec是什么
从MeasureSpec类的定义我们知道,它封装了对子View的布局要求,由尺寸和模式组成,其实MeasureSpec代表一个32位的int值,高2位表示SpecMode,低30位表示SpecSize,而SpecSize是指在某种SpecMode下的规格大小,从源码我们看出它内部定义了很多常量,从api17以后开始采用位运算,因为位运算的效率最高,我们看下三种模式:
UNSPECIFIED:未指定模式,不对View大小做限制,如:ListView,ScrollView。
EXACTLY:精确模式,确切的大小,如:100dp或者march_parent。
AT_MOST:最大模式,大小不可超过某数值,如:wrap_content。
如何优化自定义View
为了加速你的view,对于频繁调用的方法,需要尽量减少不必要的代码。先从onDraw开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。
你还需要尽可能的减少onDraw被调用的次数,大多数时候导致onDraw都是因为调用了invalidate(),因此请尽量减少调用invaildate()的次数。如果可能的话,尽量调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。
另外一个非常耗时的操作是请求layout。任何时候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每一个view的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持View的层级是扁平化的,这样对提高效率很有帮助。
如果你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操作。与内置的view不同,自定义的view可以使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。
自定义view效率高于xml定义吗
自定义view效率高于xml定义:
- 少了解析xml。
- 自定义View减少了ViewGroup与View之间的测量,包括父量子,子量自身,子在父中位置摆放,当子view变化时,父的某些属性都会跟着变化。
Draw的基本流程
绘制基本上可以分为六个步骤:
- 首先绘制View的背景;
- 如果需要的话,保持canvas的图层,为fading做准备;
- 然后,绘制View的内容;
- 接着,绘制View的子View;
- 如果需要的话,绘制View的fading边缘并恢复图层;
- 最后,绘制View的装饰(例如滚动条等等)。
setWillNotDraw的作用
如果一个View不需要绘制任何内容,那么设置这个标记位为true以后,系统会进行相应的优化。
- 默认情况下,View没有启用这个优化标记位,但是ViewGroup会默认启用这个优化标记位。
- 当我们的自定义控件继承于ViewGroup并且本身不具备绘制功能时,就可以开启这个标记位从而便于系统进行后续的优化。
- 当明确知道一个ViewGroup需要通过onDraw来绘制内容时,我们需要显示地关闭WILL_NOT_DRAW这个标记位。
invalidate()、postInvalidate()、requestLayout()的区别
- invalidate()与postInvalidate()都用于刷新View,主要区别是invalidate()在主线程中调用,若在子线程中使用需要配合handler;而postInvalidate()可在子线程中直接调用。
- invalidate()和postInvalidate():View(非容器类)调用invalidate方法只会重绘自身,ViewGroup调用则会重绘整个View树。
- requestLayout:View执行requestLayout方法,会向上递归到顶级父View中,再执行这个顶级父View的requestLayout,所以其他View的onMeasure,onLayout也可能会被调用。
网友评论