View的layout

来源:互联网 发布:域名可以干嘛 编辑:程序博客网 时间:2024/06/05 11:21

View的layout()

下面的方法解释均翻译于官方文档 /**     * layout机制有两个阶段     * 第一阶段:测量,在这个阶段,每个父view都会调用layout来为子view指定位置,最经典的做法就是使用存于measure pass()的子view测量值     * 第二阶段:分配一个大小和位置给此view和它所有的子view     * View的衍生类不应该重写这个方法,若该类有子view应该重写onLayout(),并在这个方法调用每个子view的layout()     * 上下左右的位置都是相对于该view的父控件来说的。     */    public void layout(int l, int t, int r, int b) {        if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {    /**      * onMesure()     * 测量视图和它的内容来确定宽高,注意这个方法是由measure()唤醒,并且在子类重写来为它的内容提供更精准有效的测量值。     * 基类测量的实现默认为背景的大小,除非MeasureSpec提供更大的size。子类应该重写onMeasure()为自己的内容提供更好的测量值     * 规定:当年重写这个方法时必须调用setMeasuredDimension()来保存这个view的宽高值。若是没保存成功就会触发measure()抛出IllegalStateException异常。调用父类的onMeasure()是个比较好的办法。     * 如果这个方法在子类被重写,那它应该确保测量的宽高至少是视图的最低宽高。     * @param widthMeasureSpec      * @param heightMeasureSpec      * 两个参数代表这个控件父view的宽高,并与MeasureSpec有紧密联系     */            onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);        }    /**     * setFrame()     * 为这个view分配大小和位置。此方法在layout()里调用     * 上下左右的位置都是相对于父view的     * 大小与位置与前一次有改变就会返回true     */        boolean changed = isLayoutModeOptical(mParent) ?                setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);        if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {    /**     * onLayout()     * 当这个view需要为子view分配大小和位置时会在layout()里调用它。     * 所以有子view的衍生类应该重写这个方法并调用它的每个子view的layout()。     * 5个参数的解释跟setFrame()一样。     */            onLayout(changed, l, t, r, b);        }}

总结:大致的layout过程是先调用setFrame()为这个view分配大小和位置,然后回调onLayout函数,对于View来说onLayout只是一个空实现,一般只有当它是ViewGroup需要为子view分配大小和位置时才重写它。然后它会参考measure过程中计算得到的mMeasuredWidth和mMeasuredHeight来安排子视图在父视图中显示的位置,但这不是必须的,我们可以自己传入4个参数调用layout()来安排子view具体位置。
其实具体measure()是什么时候执行的还是不清楚,找了好久也没找着,不过目前来说这个不重要就先放放吧。

MeasureSpec

上面说onMeasure(widthMeasureSpec,heightMeasureSpec)时就说到这两个参数跟MeasureSpec有密切联系,我们先就大致知道怎么用他们就行。
1. MeasureSpec.getMode(widthMeasureSpec)有三个值
- EXACTLY:测量的布局大小是精确的,比如match_parent或具体dp值。
- AT_MOST:子布局可以根据自己的大小选择任意大小。比如wrap_content,但它最大不能超出父控件大小 。
- UNSPECIFIED:父布局没有给子布局任何限制,子布局可以任意大小。这种情况大多出现与ListView 。
2. MeasureSpec.getSize(widthMeasureSpec)
得到测量大小,以像素为单位。

0 0
原创粉丝点击