1.为什么要进行Layout?
在【Android View绘制之旅】View之测量Measure过程后,View我们得到View的宽高,但光只有宽高值是不足以反映视图的,更需要知道View所在的位置。
Layout第一步:layout()方法
在【Android View绘制之旅】View之测量Measure里也说过,我们的视图树就是从线性布局开始的,所以我们仍旧是从LinearLayout研究起。
同measure一样,LinearLayout没有覆写layout方法,那么直接就看View的。
虽然View的layout方法没有加final,但是明确禁止覆写。
Derived classes should not override this method. Derived classes with children should override onLayout. In that method, they should call layout on each of their children.
layout方法的入参
入参由当前View的父组件计算得来的,具体见下面的分析。
代码中主要值得关注的地方有如下两处:
设置自身位置并判断位置同上次有无变化 见代码块A
setFrame() :layout结果执行的关键一步
- 判断一下跟Parent View的相对位置有没有发生变化
- 判断一下宽高有没有变化sizeChanged,有变化则invalidate一下(到后面draw部分可以探究)
- 将新的位置值赋值给当前View。
了解View布局的关键结果:mLeft,mRight,mTop,mBottom
拿mLeft来说,他是自身左边到父View的左边的距离,以像素为单位。
The distance in pixels from the left edge of this view’s parent to the left edge of this view.
他们都是距离上边和左边的距离。
位置同上次有变化,则执行onLayout 见代码块B
View的onLayout的实现为空,自身位置的设置已经在上面setFrame做过了,在onLayout里一般在当前View内嵌有子View的时候去遍历所有子View并逐一调用他们的layout方法。
线性布局的onLayout()方法
仍旧以代表性的layoutVertical为例子深入分析,
几个局部变量的意义
* majorGravity:线性布局垂直方向上的gravity设置
* minorGravity:线性布局水平方向上的gravity设置
* mTotalLength:分割线高度+ 子组件高度并包含自身上下Margin + 线性布局自身上下padding.
几个主要过程(layout()方法入参是如何计算出来的?在这里能找到答案):
childTop的求解
需要考虑靠上或下或居中的情况。
我们在说到是靠上 靠下 还是居中是有个前提的,就是线性布局除了容纳子组件外还有富余的空间。
富余的空间= bottom - top - mTotalLength
靠上 靠下 还是居中都是如何”处理”这些富余空间的策略而已。拿Gravity.BOTTOM来说吧:其实就是将富余空间放到上边,那么从垂直方向来说,子组件是从mPaddingTop + bottom - top - mTotalLength 开始的,(当然我们还要包括线性布局自身上部的padding.)
childLeft的求解
需要考虑靠上或下或居中的情况。
几个局部变量的意义
* width:当前线性布局的宽度
* childSpace:线性布局横向上除去padding后留给子组件的可用空间
问题:childLeft是子组件左侧到父组件左边的距离,那childLeft包含其自身的leftMargin吗?
拿左侧对齐的代码来说:
childLeft = paddingLeft + lp.leftMargin;
理解如下图:
一目了然,childLeft是不包含其自身的leftMargin,那么其他的如Top,Right类似。
childLeft的求解比较好理解就不多言了。有了上边及左边的位置,childBottom,childRight底部 和右边的位置就唾手可得了。
private void setChildFrame(View child, int left, int top, int width, int height) {
child.layout(left, top, left + width, top + height);
}
View的getMeasureWidth/Height和getWidth/Height的区别是?
说了这么多,Layout的结果是什么?
mLeft
mTop
mRight
mBottom
拥有了更新的值,这个确定了后,相对于其在父组件中的相对位置就确定了,再不停的向外延伸考虑,相对再相对,这个值确定的意义就在于其在整个视图中的绝对位置被确定了。