阅读更多
学习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