关于weight在最初 我以为它只是用来把屏幕分成若干块,然后按比重 (weight/weightSum)分配控件的宽或者高,而网上很多文章也是这么说的,直到遇见这种布局我才恍然道:想当然害人!
如图:
可以发现这种布局用RelativeLayout是没法做到很好的适配的
布局代码(这里可以自动略过,贴出来是为了让读者知道有这么回事):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="左边" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:ellipsize="end"
android:maxLines="1"
android:text="发的是会家连锁店"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="右边"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="左边" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:ellipsize="end"
android:maxLines="1"
android:text="发的是会家连锁店"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="右边"
/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="左边" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:ellipsize="end"
android:maxLines="1"
android:text="发的是会计法就死定了房间里苏菲的世界浪费就爱上了对方家连锁店"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="右边"
/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="左边" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:text="京东方老司机是大佬附件是垃圾地方零售价爱对方了坚实的了解阿拉斯加地方了空间撒大家解放啦塞口袋街坊邻居阿萨德理解看见的立法及胜利大街发的是会计法就死定了房间里苏菲的世界浪费就爱上了对方家连锁店"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="右边"
/>
</LinearLayout>
</LinearLayout>
我想要的适配效果是第三种,来看它的布局:
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="左边" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:ellipsize="end"
android:maxLines="1"
android:text="发的是会计法就死定了房间里苏菲的世界浪费就爱上了对方家连锁店"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="右边"
/>
</LinearLayout>
文本超过一行就省略这个没什么好说的,关键在于:
中间的文本给了weight=“1” 并且左右两边的布局都给的warp_content (weight默认是为0)
为了搞清楚,于是对LinearLayout的 measure 源码进行了一顿瞎读~后来发现其实LinearLayout中的子视图如果设置过weight 其实也要进行 两次测量(RelativeLayout无论如何都会进行两次测量)
下面是总结(这段文字来源 是一篇对LinearLayout源码解析的):
父视图是match_parent(或者精确值),子视图拥有weight,并且宽度或者高度给定为0:
子视图的宽度或者高度比例将会跟我们分配的layout_weight一致,原因在于weight二次测量时走了else分支,传入的是计算出来的share值父视图是match_parent(或者精确值),子视图拥有weight,但宽度或者高度给定为match_parent(或者精确值):
子视图宽度或者高度比例将会跟我们分配的layout_weight相反,原因在于在此之前子视图测量过一次,同时子视图的测量宽度或者高度为父视图的宽度或者高度,在计算剩余空间的时候得出一个负值,加上自身的测量宽度或者高度的时候反而更小父视图是wrap_content,子视图拥有weight
子视图的宽度或者高度将会强行置为其wrap_content给的值并以wrap_content模式进行测量父视图是wrap_content,子视图没有weight:
子视图的宽度或者高度跟其他的viewgroup一致
下面是截自LinearLayout 的Measure 源码(源码分析现在还不打算写,主要是我太懒~~~)
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
float childExtra = lp.weight;
if (childExtra > 0) {
// share(剩余宽度或高度)*(子控件的weight/weightSum),也就是子控件weight占比*剩余高度
int share = (int) (childExtra * delta / weightSum);
// weightSum计余
weightSum -= childExtra;
// 剩余宽度或者高度
delta -= share;
final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
mPaddingLeft + mPaddingRight +
lp.leftMargin + lp.rightMargin, lp.width);
if ((lp.width!= 0) || (widthMode != MeasureSpec.EXACTLY)) {
int childWidth = child.getMeasuredWidth() + share;
if (childWidth < 0) {
childWidth = 0;
}
child.measure(childWidthMeasureSpec,
MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
} else {
child.measure(childWidthMeasureSpec,
MeasureSpec.makeMeasureSpec(share > 0 ? share : 0,
MeasureSpec.EXACTLY));
}
可以看见
child.measure(childWidthMeasureSpec,MeasureSpec.makeMeasureSpec(share > 0 ? share : 0,MeasureSpec.EXACTLY));
这里返回的是具体的测量宽度值 而这个share 计算公式:
//share(剩余宽度或高度)*(子控件的weight/weightSum),也就是子控件weight占比*剩余宽度(或者高度)
int share = (int) (childExtra * delta / weightSum);
如图的情况也就是
左边:width = 文字多宽就多宽
右边:width = 文字多宽就多宽
share = (int) 中间文字的宽度 * 1/1 = 中间文字多宽就多宽
最后总结下对weight的理解应该是:用于分配LinearLayout剩下的空间!!!