学习android以来,对于layout_weight属性一直很迷惑,感觉网上多都不靠谱,全是凭实验试出来的规律。于是就看了下源码才恍然大悟。废话不多说了直入主题。
源码(有省略)
LinearLayout类中

void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
。。。。。。。。。。。。
float totalWeight = 0;//总的权重
final int count = getVirtualChildCount();//子控件个数
。。。。。。。。。。。
for (int i = 0; i < count; ++i) {//依次遍历每一个控件
final View child = getVirtualChildAt(i);

if (child == null) {
mTotalLength += measureNullChild(i);//计算控件总长度
continue;
}

。。。。。。。。。。

if (hasDividerBeforeChildAt(i)) {
mTotalLength += mDividerWidth;//计算控件总长度
}

final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
child.getLayoutParams();

totalWeight += lp.weight;//计算总的权重
。。。。。。。。。。。

。。。。。。。。
int delta = widthSize - mTotalLength;//计算剩余空间(可为负数,widthSize为layout宽度)

if (delta != 0 && totalWeight > 0.0f) {//如果剩余空间不为0,且有权重从新计算大小
float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
。。。。。。。。。。。。。
mTotalLength = 0;

for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
。。。。。。。。。。。。。。
final LinearLayout.LayoutParams lp =
(LinearLayout.LayoutParams) child.getLayoutParams();

float childExtra = lp.weight;
if (childExtra > 0) {//如果子控件有权重且大于0,则分配剩余空间
// Child said it could absorb extra space -- give him his share
int share = (int) (childExtra * delta / weightSum);//根据权重获得分配空间
weightSum -= childExtra;//总权重减去已分配的控件的权重
delta -= share;//总的剩余空间减去已分配的剩余空间


。。。。。。。。
//根据分配到的空间从新计算子控件的宽度
if ((lp.width != 0) || (widthMode != MeasureSpec.EXACTLY)) {
// child was measured once already above ... base new measurement
// on stored values
int childWidth = child.getMeasuredWidth() + share;
if (childWidth < 0) {
childWidth = 0;
}

child.measure(
MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
childHeightMeasureSpec);
} else {
// child was skipped in the loop above. Measure for this first time here
child.measure(MeasureSpec.makeMeasureSpec(
share > 0 ? share : 0, MeasureSpec.EXACTLY),
childHeightMeasureSpec);
}

// Child may now not fit in horizontal dimension.
。。。。。。。
}

。。。。。。
。。。。。。。。。。。




总结:
注意红字部分。
layout_weight的控件的计算流程(注意:weightsum为浮点数,作为除数时不会抛异常)
1:遍历每一个控件,计算控件的大小,记录总的权重,总的空间大小和。
2:计算剩余空间(可以为负数)
3:再次遍历每个控件,更具权重从新计算控件大小。
3.1:取一个控件,计算分配到的剩余空间
share = (int) (childExtra * delta / weightSum);
3.2 总的剩余空间减去已分配的
delta -= share
3.3 总的权重减去已经分配的控件的
weightSum -= childExtra;
3.4重复3.1

例子:
假设:3个Button的比例应该为1:1:2,三个按钮的宽度都是FILL_PARENT,layout宽度为一个屏幕宽度width。
所以:
第一次计算 button1的宽度是width,button2的宽度是width,button3的宽度是width.
总长度 totalLength = 3*width;
总权重 totalWeight = 1+1+2 = 4;
屏幕空间 为 widthSize = width
剩余空间 delta = widthSize -totalLength = widh - 3*width = -2*width;
第二次计算
根据权重再次计算button1宽度
分配剩余空间空间 share = delta*1/totalWeight = (-2*wdth)*1/4=-width/2;
button1的宽度buttonwidth 为第一次计算的宽度width加上分配到的剩余空间即 width+(-width/2)= width/2;
从新计算剩余空间和权重和
delta = delta - share = -3/2*width
totalWeight = totalWeight - button1的 weight = 4-1=3
根据权重再次计算button2宽度
分配剩余空间空间 share = delta*1/totalWeight = (-3/2*wdth)*1/3=-width/2;
button2的宽度buttonwidth 为第一次计算的宽度width加上分配到的剩余空间即 width+(-width/2)= width/2;
从新计算剩余空间和权重和
delta = delta - share = -3/2*width + width/2 = -width
totalWeight = totalWeight - button2的 weight = 2-1=2
根据权重再次计算button3宽度
分配剩余空间空间 share = delta*1/totalWeight = (-wdth)2/2=-width;
button3的宽度buttonwidth 为第一次计算的宽度width加上分配到的剩余空间即 width+(-width)= 0;
从新计算剩余空间和权重和
delta = delta - share = -width + width = 0
totalWeight = totalWeight - button3的 weight = 2-2=0

更多相关文章

  1. android ImageView 图片宽度全屏,高度自适应的写法
  2. 自定义Dialog步骤
  3. Android(安卓)抽屉效果
  4. ConstraintLayout约束布局属性
  5. 自定义简单的ProgressBar
  6. Android如何一步步实现状态栏一体化效果
  7. Android(安卓)为什么TextView文本有内容却显示为空?
  8. Android获取内部和SDCard的存储空间
  9. android staticlayout使用讲解

随机推荐

  1. Android窗体悬浮在另一个窗体
  2. android 设置app版本号
  3. Android(安卓)聊天软件实现
  4. Android动画效果生动有趣的通知NiftyNoti
  5. Android深入四大组件(一)应用程序启动过程
  6. Android(安卓)Studio安装教程(超详细教程)
  7. Android动画效果生动有趣的通知NiftyNoti
  8. android屏幕监视工具 android screen mon
  9. Android内核开发:开发板选购
  10. [Android] 基于 Linux 命令行构建 Androi