View的layout

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值