LinearLayout——线性布局(下)
来源:互联网 发布:ubuntu 安装 kde桌面 编辑:程序博客网 时间:2024/05/24 06:12
本文部分内容参考:http://blog.csdn.net/kkkvvv123/article/details/9029381
LinearLayout中的weight属性(在子View下设置)是非常重要的一个属性,他可以做到n等分一行的空间,使得子View可以均匀的分布在布局空间内。也可以按照要求按比例分配空间。这在多分辨率适配中是个很有力的武器。weightSum是配合weight使用的。下面先来分析LinearLayout的源码了解weight实现的原理。
源码片段:
/* *delta 额外空间 *widthSize LinearLayout的宽度 *mTotalLength 所有子View的宽度的和(还没有考虑layout_weight) *totalWeight: 所有子View的layout_weight的和 *mWeihtSUm: LinearLayout的android:weightSum属性 */ //计算额外空间 int delta = widthSize - mTotalLength; //必须有额外空间存在且有weight设置 if (delta != 0 && totalWeight > 0.0f) { //如果LinearLayout的android:weightSum设置则weightSum等于设定值 //否则为totalWeight float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight; //将根Gravity有关的偏移初始化 maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1; maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1; maxHeight = -1; mTotalLength = 0; //count为子View的个数 for (int i = 0; i < count; ++i) { final View child = getVirtualChildAt(i); //如果为null或View.GONE则跳过 if (child == null || child.getVisibility() == View.GONE) { continue; } final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); //可见weight属性应为float float childExtra = lp.weight; if (childExtra > 0) { //当前View占额外空间的比例, 注意这个是取整的! //delta为负数的话这里的share也为负数 int share = (int) (childExtra * delta / weightSum); //分配完成后,在总量里面减去已分配部分 weightSum -= childExtra; delta -= share; final int childHeightMeasureSpec = getChildMeasureSpec( heightMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin, lp.height); // TODO: Use a field like lp.isMeasured to figure out if this // child has been previously measured // MeasureSpec.EXACTLY代表之前已经给定确定的size //之后即使在改变size至少也要比当前给定的大 if ((lp.width != 0) || (widthMode != MeasureSpec.EXACTLY)) { // child was measured once already above ... //base new measurement // on stored values //如果结果为负数则Width等于0 int childWidth = child.getMeasuredWidth() + share; if (childWidth < 0) { childWidth = 0; } //将当前View按新的Width去measure 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); } }
源码中关键部分为
//计算额外空间(当赋给width的值大于LinearLayout的width时可能为负数) int delta = widthSize - mTotalLength;
int share = (int) (childExtra * delta / weightSum); //分配完成后,在总量里面减去已分配部分 weightSum -= childExtra; delta -= share;
int childWidth = child.getMeasuredWidth() + share; if (childWidth < 0) { childWidth = 0; }
SDK中对LinearLayout的介绍http://developer.android.com/guide/topics/ui/layout/linear.html中有一块对weight平分的实现进行了说明:
Equally weighted children
To create a linear layout in which each child uses the same amount of space on the screen, set the android:layout_height
of each view to "0dp"
(for a vertical layout) or theandroid:layout_width
of each view to "0dp"
(for a horizontal layout). Then set theandroid:layout_weight
of each view to "1"
.
通过sdk的说明也可以知道,weight是对剩余空间的分配而不是对LinearLayout空间的分配!千万不要想当然……下面举几个例子,看看weight和weightSum到底怎么使用。
例1:weightSum为默认值,子View的width=match_parent,weight分别为: 1 1 2
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <Button android:layout_weight="1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 1"/> <Button android:layout_weight="1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 2"/> <Button android:layout_weight="2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button 3"/> </LinearLayout>
效果图:
第三个button为什么不见了呢?下面来看一些计算就能明白了。
设:屏幕最大宽度为PM
delta = PM - 3 * PM = -2PM
mWeightSum = 1.0F + 1.0F + 2.0F = 4.0F
第一个按钮:
float childExtra = lp.weight = 1.0F
share = (int) (childExtra* delta / mWeightSum) =(int)( 1.0F * (-2PM) / 4.0F ) = -0.5PM
childWidth = PM + share = 0.5PM //第一个按钮的宽是屏幕最大宽度的一半
weightSum -= childExtra(weightSum= 3)
delta -= share ( delta = -1.5PM )
第二个按钮:
float childExtra = lp.weight = 1.0F
share = (int) (childExtra* delta / mWeightSum) =(int)( 1.0F * (-1.5PM) / 3.0F ) = -0.5PM
childWidth = PM + share = 0.5PM //第二个按钮的宽也是屏幕最大宽度的一半
weightSum -= childExtra(weightSum= 2)
delta -= share ( delta = -PM )
第三个按钮:
float childExtra = lp.weight = 1.0F
share = (int) (childExtra* delta / mWeightSum) =(int)( 2.0F * PM / 2.0F ) = -PM
childWidth = PM + share = 0 //第三个按钮的宽是0
例2:如果weight分别为: 1 1 3,代码省略直接看效果
上图可以看到Button2右边不见了!仿照例1的计算可以得出Button1的width=3/5PM,Button2的width=3/5PM!他们的和大于PM所以右边会不见啦。
其实可以根据源码里的公式列出一个不等式组然后解出一个关系式:
k是子View的个数,wj是某一个子View的weight,不等式右边是所有weight的和。
当不等式左边等于右边,那么会出现例1的情况
当不等式左边大于右边,那么会出现例2的情况
当不等式左边小右边,那么会保证所有子View在LinearLayout里
接着说weightSum,这个属性是手动设所有定子View的weight和。如果这个weightSum的值小于所有子View的weight的和,那么会出现类似上面说过的2个问题。所以一般weightSum会比所有weight的和大,这样能实现类似缩放的功能,当然只是缩小没有放大!有源码在,分析应该没问题了,具体效果还是大家自己去尝试下吧!
- LinearLayout——线性布局(下)
- LinearLayout—线性布局
- LinearLayout——线性布局
- LinearLayout——线性布局(上)
- Android【布局管理器】——线性布局LinearLayout
- Android基础入门教程——2.2.1 LinearLayout(线性布局)
- Android基础入门教程——2.2.1 LinearLayout(线性布局)
- Android基础入门教程——2.2.1 LinearLayout(线性布局)
- 控件布局——LinearLayout(下)
- Android 线性布局:LinearLayout
- LinearLayout 线性布局管理器
- LinearLayout(线性布局)
- LinearLayout:线性布局基础
- 线性布局LinearLayout
- LinearLayout线性布局
- LinearLayout(线性布局)
- LinearLayout线性布局
- LinearLayout(线性布局)
- Struts2 学习笔记04 路径问题
- VMware 虚拟机安装 MAC OS X 过程
- sqlmap实例拿站
- ios绘图
- android滑动值的计算
- LinearLayout——线性布局(下)
- 程序员学英语三部曲
- HDU4417-树状数组2012 ACM/ICPC Asia Regional Hangzhou Online
- s5pv210下的wmv8960驱动
- QT为QLabel添加Click事件
- 区分keydown和keypress事件
- 欧拉函数性质
- centos6.4最小安装版 pppoe上网配置 无线上网配置
- STL中的vector_map