外观
measure 和 layout 的区别?getWidth 与 getMeasuredWidth 呢?
标准回答
measure 得到测量宽高;layout 由父容器安排孩子的 left、top、right、bottom,确定最终边界。getMeasuredWidth 读取测量结果,getWidth 则是最终布局边界的 right 减 left。
正常布局中,两者常常相同,但含义不同。孩子测量完、尚未布局时,可能已经有 measuredWidth,却还没有本轮最终 width。自定义父容器也可能用与测量结果不同的边界放置孩子,因此不能认为这两个值永远相等。
ViewGroup 通常在 onMeasure 测量孩子,在 onLayout 调用孩子的 layout 安排位置。孩子的 left 和 top 是相对父容器的布局位置,不是它在整个屏幕上的绝对坐标。translationX / translationY 还可能改变视觉位置,而不改写原来的 left / top。
关键机制
- 自定义 ViewGroup 需要同时处理测量与排布,不能只给自己设置一个大小。
- getX 通常体现 left 与 translationX 的组合;获取屏幕位置应使用对应坐标 API。
- padding 影响自身内容区;margin 是父容器排布孩子时遵循的外部间距,具体支持由 LayoutParams 决定。
通俗例子
按钮 layout 到 left=20、right=120 时宽度是 100。再设置 translationX=30,视觉上向右移动,但它的布局 left 仍然可以是 20。
追问与回答
为什么 getWidth 在 onCreate 里经常为 0?
onCreate 中通常只是创建并设置了内容,窗口的后续布局还没有完成。此时读到的 0 不代表 XML 配错了。依赖最终尺寸的计算应该放到布局完成的回调,或者自定义 View 的 onSizeChanged 等合适阶段。
易混淆点
控件尺寸与坐标取决于所处阶段和坐标系。截图上的位置不一定等于 getLeft 返回值。
参考资料
内容来源
- Android 技术札记 · 原条目
layout-bounds