关键注释已经在代码中写好了,我们可以从中发现,onLayout的关键就是在于确定子view的上下左右四个边界的位置。而FrameLayout的布局过程中,所有子view的布局都是独立的,而不会受到其他子view的影响,这也验证了FrameLayout的特性:所有子view都会叠加排列。如果是竖向布局的LinearLayout,那么每次下一个子view的top都会建立在上一个子view的bottom位置的基础上来计算,以保证它们是顺序排列的,这一点可以自己查看LinearLayout的onLayout()函数验证。
也许有人会问,这只是测量了位置,但是还没有应用到视图啊。其实设置不在onLayout()函数,而是早在View的layout()函数中就进行了。就是setFrame()函数,changed就是setFrame()函数的返回值。从这里也可以看出,子view的位置(应该)完全是由父layout确定的,并且在父layout调用子view的layout()函数中直接设置了位置。不建议强行在onLayout()函数中再次调用setFrame(),避免出现布局错乱。onLayout()函数应该只用来布局子view,或者进行其他需要在layout阶段进行的工作,比如打log。如果自定义view是一个view而不是layout,那么完全不用重写onLayout()也是可以的。
2.2 FrameLayout属性验证在布局过程中看到,在不改变FrameLayout的布局方向的情况下(毕竟改变布局方向的情况很少),只有子view的gravity和margin值能影响子view的位置。接下来会验证一些特性。
(1) 无任何特殊设置
新建一个布局,没有任何特殊选项来看看效果
效果
(2) 子view添加margin
修改布局TextView,添加margin
效果
这里我们有个现象可以看一下,如果设置marginLeft值一直到TextView的右边界超出FrameLayout的右边界,会出现什么情况。
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="test" android:textSize="35sp" android:textColor="#ff3467" android:layout_marginTop="30dp" android:layout_marginLeft="330dp"/>我们发现TextView居然折行了。显然子view是也可以得到父layout的布局信息的,并且在布局过程中会自动进行某些改变。虽然这一点来说是比较智能的,但不可避免的会出现某些不希望出现的情况。如果不希望出现子view自做主张的情况,在measure时可以构建一个UNSPECIFIED的MeasureSpec来测量子view。
(3) 子view添加layout_gravity
修改布局TextView,添加gravity <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="test" android:textSize="35sp" android:textColor="#ff3467" android:layout_gravity="center"/>
效果
(4) FrameLayout修改layoutDirection
去掉TextView的margin和gravity,然后在FrameLayout中添加下面一句,就可以修改FrameLayout的布局方向为从右到左
效果
从以上过程,我想大伙儿应该已经完全能理解FrameLayout的布局过程,也顺便从代码中了解了一些FrameLayout其他的特性并且做了验证。
2.3 layout过程总结layout的一般过程就是如此,总结起来就是如下几步:
当然,以上说的还是ViewGroup的layout过程,如果是View的layout过程就会更加简单,毕竟没有子view,只要将传进来的位置应用到视图上就OK。
3. draw过程draw过程相比与其他的两个就简单多了。它的作用就是把view内容绘制到屏幕上。