LinearLayout的weight
来源:互联网 发布:樱井知香为什么喷泉 编辑:程序博客网 时间:2024/05/16 12:58
一、weight是怎么计算的
使用LinearLayout的时候,一定会遇到weight怎么使用的问题。
简单来讲,假设LinearLayout为竖直方向
子View 的高度 = 子View 的实际高度 + 分配到的高度
实际高度:是该View的height,例如:在xml中设置的android:layout_height=”8dp”(注意这里设置的不是wrap_content或者match_parent)
分配到的高度 : (LinearLayout自身的高度 - 所有子View的总高度) / weight总和 * 该子View的weight
LinearLayout自身的高度 - 所有子View的总高度 的含义为:LinearLayout的可分配高度
所以简单来说,子View的高度 = 自身高度 + LinearLayout分配给的高度。LinearLayout是用自身可分配的高度,分成“weight总和”份,然后再按照每个子View的weight值分配。
二、例子
1、先看没加weight的时候的样子:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="aaaaaaaaaaaaaaa" android:background="#ff0000" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="bbb" android:background="#00ff00" /></LinearLayout>
可以看到,第一个 TextView 的宽度为 15个a 的宽度,第二个 TextView 的宽度为 3个b 的宽度。
2、添加weight:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="aaaaaaaaaaaaaaa" android:layout_weight="1" android:background="#ff0000" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="bbb" android:layout_weight="1" android:background="#00ff00" /></LinearLayout>
这就是大家最常遇到的问题,就是明明 weight 设置的一样,但是实际上的效果并不是均分。
为什么会这样呢?
看第一张图(也就是没加weight的那张图),图中,第一行,除去红色和绿色的部分是:LinearLayout除去 所有 子View 的总宽度 之后剩下的宽度,这部分才是使用weight分配的部分。
所以,
第一个TextView的总宽度是:第一个TextView的实际宽度为15个a的宽度 + LinearLayout剩余部分的一半
第二个TextView的总宽度是:第二个TextView的实际宽度为3个b的宽度 + LinearLayout剩余部分的一半
于是,虽然weight相同,但是不均分。
3、实现均分:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:text="aaaaaaaaaaaaaaa" android:layout_weight="1" android:background="#ff0000" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:text="bbb" android:layout_weight="1" android:background="#00ff00" /></LinearLayout>
其实想要均分的方法很简单,就是把每个 子View 的 layout_width 置为 0dp 即可。
为什么这样就可以了呢?
因为 所有子View 的 width 都为 0dp,所以,LinearLayout可分配的总宽度为全部宽度,即屏幕总宽度。
又因为 所有子View 的 总weight值为2,所以,每份weight可以分到屏幕总宽度的一半。
所以,
第一个TextView的总宽度是:0 + LinearLayout剩余部分的一半(屏幕的一半)
第二个TextView的总宽度是:0 + LinearLayout剩余部分的一半(屏幕的一半)
于是,子View 的 layout_width 置为 0dp,均分了。
4、子View 的 layout_width 置为 match_parent
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="aaaaaaaaaaaaaaa" android:layout_weight="1" android:background="#ff0000" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="bbb" android:layout_weight="1" android:background="#00ff00" /></LinearLayout>
可以看到,也可以均分。
这里的实现与 layout_width 置为 0dp 是不同的,虽然效果是一样的,可是过程不同。
因为 所有子View 的 layout_width 都为 match_parent,子View的宽度 = LinearLayout的宽度 = 屏幕宽度
所以,LinearLayout可分配的总宽度为:
自身宽度 - 所有子View的宽度和
= 屏幕宽度 - 屏幕宽度 * 2(乘以2 是因为 2个子View 宽度都为屏幕宽度)
= -屏幕宽度
又因为 所有子View 的 总weight值为2,所以,每份weight可以分到 负的屏幕总宽度的一半。
所以,
第一个TextView的总宽度是:屏幕宽度 + LinearLayout剩余部分的一半(负的屏幕的一半) = 屏幕的一半
第二个TextView的总宽度是:屏幕宽度 + LinearLayout剩余部分的一半(负的屏幕的一半) = 屏幕的一半
于是,子View 的 layout_width 置为 match_parent,均分了。
5、验证子View 的 layout_width 置为 match_parent 与 0dp 的效果
先验证 0dp:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:text="aaaaaaaaaaaaaaa" android:layout_weight="1" android:background="#ff0000" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:text="bbb" android:layout_weight="2" android:background="#00ff00" /></LinearLayout>
因为 所有子View 的 width 都为 0dp,所以,LinearLayout可分配的总宽度为全部宽度,即屏幕总宽度。
又因为 所有子View 的 总weight值为3,所以,每份weight可以分到屏幕总宽度的1/3。
所以,
第一个TextView的总宽度是:0 + LinearLayout剩余部分的1/3(屏幕的1/3) * 1(weight = 1) = 屏幕的 1/3
第二个TextView的总宽度是:0 + LinearLayout剩余部分的1/3(屏幕的1/3) * 2(weight = 2) = 屏幕的 2/3
再验证match_parent:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="aaaaaaaaaaaaaaa" android:layout_weight="1" android:background="#ff0000" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="bbb" android:layout_weight="2" android:background="#00ff00" /></LinearLayout>
因为 所有子View 的 layout_width 都为 match_parent,子View的宽度 = LinearLayout的宽度 = 屏幕宽度
所以,LinearLayout可分配的总宽度为:
自身宽度 - 所有子View的宽度和
= 屏幕宽度 - 屏幕宽度 * 2(乘以2 是因为 2个子View 宽度都为屏幕宽度)
= -屏幕宽度
又因为 所有子View 的 总weight值为3,所以,每份weight可以分到 负的屏幕总宽度的1/3。
所以,
第一个TextView的总宽度是:屏幕宽度 + LinearLayout剩余部分的1/3(负的屏幕的1/3) * 1(weight = 1) = 屏幕的2/3
第二个TextView的总宽度是:屏幕宽度 + LinearLayout剩余部分的1/3(负的屏幕的1/3) * 2(weight = 2) = 屏幕的1/3
有了以上的例子,想必已经知道 LinearLayout 的 weight 的计算方式了,接下来看看源码中是怎么计算的。
三、源码中 weight 的计算
下面源码只截取了计算 weight 的一小部分,LinearLayout为水平的,计算的是width
// widthSize 为整个LinearLayout的宽度,mTotalLength 为所有child测量出的宽度和,delta为可分配宽度 int delta = widthSize - mTotalLength; // totalWeight 是所有child的weight的和 if (delta != 0 && totalWeight > 0.0f) { // weightSum一般等于totalWeight float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; ...... mTotalLength = 0; for (int i = 0; i < count; ++i) { final View child = getVirtualChildAt(i); if (child == null || child.getVisibility() == View.GONE) { continue; } final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); float childExtra = lp.weight; if (childExtra > 0) { // 算出child分配到的宽度 int share = (int) (childExtra * delta / weightSum); // 减去现在的weight weightSum -= childExtra; // 减去现在的宽度 delta -= share; // 计算子View高度上的MeasureSpec final int childHeightMeasureSpec = getChildMeasureSpec( heightMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin, lp.height); if ((lp.width != 0) || (widthMode != MeasureSpec.EXACTLY)) { // 如果是 wrap_content 或者 match_parent,lp.width不为0,会执行这里 // 宽度 = 自身宽度 + 分配宽度 int childWidth = child.getMeasuredWidth() + share; if (childWidth < 0) { childWidth = 0; } child.measure( MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY), childHeightMeasureSpec); } else { // child的width为0dp时,执行else // 宽度 = 分配宽度 child.measure(MeasureSpec.makeMeasureSpec( share > 0 ? share : 0, MeasureSpec.EXACTLY), childHeightMeasureSpec); } childState = combineMeasuredStates(childState, child.getMeasuredState() & MEASURED_STATE_MASK); } ...... } ...... }
原创文章,转载请注明出处,谢谢~
- LinearLayout的weight
- LinearLayout中weight的学习
- android LinearLayout的weight问题
- LinearLayout的weight(权值)详解
- 浅析LinearLayout的weight属性
- LinearLayout的weight(权重属性)
- 对LinearLayout中Weight的深度分析
- LinearLayout设置 weight 无法绘制的问题
- 相对布局LinearLayout权重weight的用法
- 关于LinearLayout中的weight的属性
- LinearLayout布局中的weight的理解
- LinearLayout内的权重属性 weight
- LinearLayout中的weight属性的计算
- Android-LinearLayout的weight属性分配原则分析
- 五.LinearLayout的gravity,layout_gravity和weight
- LinearLayout中的weight属性的计算
- LinearLayout(线性布局)中weight的难点
- LinearLayout 中的 weight 属性
- Intent 传递List<Object>
- mysql中的timestamp和date
- 工程师的好坏在于怎么提取出有效的需求,去掉不需要解决的问题
- 7/18android培训第8天
- redis JAVA客户端(Jedis)测试使用
- LinearLayout的weight
- Android EventBus框架的使用
- 设计模式 -- 策略模式
- 使用DialogFragment
- C++基础:运算符重载
- LeetCode--No.101--Symmetric Tree
- 学习之maven(2)
- 浅谈c语言基础程序结构
- Linux 解压命令