当前位置: 代码迷 >> 移动开发 >> (原创)关于LinearLayout中layout_weight属性的实情
  详细解决方案

(原创)关于LinearLayout中layout_weight属性的实情

热度:3395   发布时间:2013-02-26 00:00:00.0
(原创)关于LinearLayout中layout_weight属性的真相
LinearLayout中layout_weight的使用
这是一个让人费解的属性.
先在网上收集一下关于weight的用法,大致的总结如下:
1.权值越小,重要度越高.
2.?image001.png
3.?image004.gif
4.?image006.gif

?

我凌乱了,这个到底是个什么情况!

?

还是先看google给出的官方文档:
http://developer.android.com/guide/topics/ui/layout/linear#Weight
  1. <?xml version="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:paddingLeft="16dp"
  6. android:paddingRight="16dp"
  7. android:orientation="vertical">
  8. <EditText
  9. android:layout_width="fill_parent"
  10. android:layout_height="wrap_content"
  11. android:hint="@string/to"/>
  12. <EditText
  13. android:layout_width="fill_parent"
  14. android:layout_height="wrap_content"
  15. android:hint="@string/subject"/>
  16. <EditText
  17. android:layout_width="fill_parent"
  18. android:layout_height="0dp"
  19. android:layout_weight="1"
  20. android:gravity="top"
  21. android:hint="@string/message"/>
  22. <Button
  23. android:layout_width="100dp"
  24. android:layout_height="wrap_content"
  25. android:layout_gravity="right"
  26. android:text="@string/send"/>
  27. </LinearLayout>
复制代码
其效果如下:
image007.jpg?

大概了解到,使用weight属性可以让子组件share父容器剩余的空间.
文档边上还有一段tips:
Tocreate a linear layout in which each child uses the same amount of space on thescreen, set the?android:layout_heightofeach view to?"0dp"(fora vertical layout) or theandroid:layout_widthofeach view to?"0dp"(fora horizontal layout). Then set theandroid:layout_weightofeach view to?"1".
此方法可以让子组件平均分配父容器的空间.
于是我尝试了一下
  1. <?xmlversion="1.0" encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical">
  6. <LinearLayout
  7. android:layout_width="fill_parent"
  8. android:layout_height="100dp"
  9. android:orientation="horizontal">
  10. <TextView
  11. android:layout_width="0dp"
  12. android:layout_height="fill_parent"
  13. android:layout_weight="1"
  14. android:background="#aa0000"
  15. android:gravity="center"
  16. android:text="1" />
  17. <TextView
  18. android:layout_width="0dp"
  19. android:layout_height="fill_parent"
  20. android:layout_weight="2"
  21. android:background="#00aa00"
  22. android:gravity="center"
  23. android:text="2" />
  24. <TextView
  25. android:layout_width="0dp"
  26. android:layout_height="fill_parent"
  27. android:layout_weight="3"
  28. android:background="#aa0000"
  29. android:gravity="center"
  30. android:text="3" />
  31. </LinearLayout>
  32. </LinearLayout>
复制代码

image008.jpg?

不错,?大小和weight成正比!!
接着我想学以致用:
  1. <?xmlversion="1.0" encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical">
  6. <LinearLayout
  7. android:layout_width="fill_parent"
  8. android:layout_height="100dp"
  9. android:orientation="horizontal">
  10. <TextView
  11. android:layout_width="fill_parent"
  12. android:layout_height="fill_parent"
  13. android:layout_weight="1"
  14. android:background="#aa0000"
  15. android:gravity="center"
  16. android:text="1" />
  17. <TextView
  18. android:layout_width="fill_parent"
  19. android:layout_height="fill_parent"
  20. android:layout_weight="2"
  21. android:background="#00aa00"
  22. android:gravity="center"
  23. android:text="2" />
  24. </LinearLayout>
  25. </LinearLayout>
复制代码
效果如下:
image009.jpg?
汗,怎么成反比了(我把0dp改成了fill_parent)
接着我尝试加个view试试,
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. ? ? android:layout_width="match_parent"
  4. ? ? android:layout_height="fill_parent"
  5. ? ? android:orientation="vertical" >
  6. ? ? <LinearLayout
  7. ? ?? ???android:layout_width="fill_parent"
  8. ? ?? ???android:layout_height="100dp"
  9. ? ?? ???android:orientation="horizontal">
  10. ? ?? ???<TextView
  11. ? ?? ?? ???android:layout_width="fill_parent"
  12. ? ?? ?? ???android:layout_height="fill_parent"
  13. ? ?? ?? ???android:layout_weight="1"
  14. ? ?? ?? ???android:background="#aa0000"
  15. ? ?? ?? ???android:gravity="center"
  16. ? ?? ?? ?? ?android:text="1"/>
  17. ? ?? ???<TextView
  18. ? ?? ?? ???android:layout_width="fill_parent"
  19. ? ?? ?? ???android:layout_height="fill_parent"
  20. ? ?? ?? ???android:layout_weight="2"
  21. ? ?? ?? ???android:background="#00aa00"
  22. ? ?? ?? ???android:gravity="center"
  23. ? ?? ?? ???android:text="2"/>
  24. ? ?? ???
  25. ? ?? ???<TextView
  26. ? ?? ?? ???android:layout_width="fill_parent"
  27. ? ?? ?? ???android:layout_height="fill_parent"
  28. ? ?? ?? ???android:layout_weight="3"
  29. ? ?? ?? ???android:background="#00aa00"
  30. ? ?? ?? ???android:gravity="center"
  31. ? ?? ?? ???android:text="3"/>
  32. ? ? </LinearLayout>
  33. </LinearLayout>
复制代码
?
怎么还是这个效果,不理解!!
然后我试试改weight值
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. ? ? android:layout_width="match_parent"
  4. ? ? android:layout_height="fill_parent"
  5. ? ? android:orientation="vertical" >
  6. ? ? <LinearLayout
  7. ? ?? ???android:layout_width="fill_parent"
  8. ? ?? ???android:layout_height="100dp"
  9. ? ?? ???android:orientation="horizontal">
  10. ? ?? ???<TextView
  11. ? ?? ?? ???android:layout_width="fill_parent"
  12. ? ?? ?? ???android:layout_height="fill_parent"
  13. ? ?? ?? ???android:layout_weight="2"
  14. ? ?? ?? ???android:background="#aa0000"
  15. ? ?? ?? ???android:gravity="center"
  16. ? ?? ?? ???android:text="2"/>
  17. ? ?? ???<TextView
  18. ? ?? ?? ???android:layout_width="fill_parent"
  19. ? ?? ?? ???android:layout_height="fill_parent"
  20. ? ?? ?? ???android:layout_weight="3"
  21. ? ?? ?? ???android:background="#00aa00"
  22. ? ?? ?? ???android:gravity="center"
  23. ? ?? ?? ???android:text="3"/>
  24. ? ?? ???
  25. ? ?? ???<TextView
  26. ? ?? ?? ???android:layout_width="fill_parent"
  27. ? ?? ?? ???android:layout_height="fill_parent"
  28. ? ?? ?? ???android:layout_weight="4"
  29. ? ?? ?? ???android:background="#00aa00"
  30. ? ?? ?? ???android:gravity="center"
  31. ? ?? ?? ???android:text="4"/>
  32. ? ? </LinearLayout>
  33. </LinearLayout>
复制代码
image010.png
囧!
Google的android大神们,我凌乱了!
Android屌丝程序员毅然决定去看源码:
从ViewGroup的measure方法开始,接着到LinearLayout的measureVertical方法(假设linear是垂直分布的,水平类似),有以下代码片段:image013.gif
翻译: 如果linear的尺寸Mode为EXACTLY, 并且该子组件的height为0,weight>0,则这次不计算组件的高度,下面再计算.
接着往下看:
image015.gif


image017.gif?

翻译:
delta为子组件第一次计算完后,linear还剩余多少高度。
Share为第二次子组件能够分配到的剩余空间。
这个样看来,由于把子组件的属性改为fill_parent(height值为-1)之后,子组件的高度被计算了两次.
若有2个组件, 权值分别为1 , 2, 设宽度为X,则计算如下:
Delta =x - 2x(第一次计算) = -x(囧,这个值居然是负的);
X1 = x+ share1 = x + (delta * 1 / 3) = 2/3x(第一次计算的值和剩余的相加)
X2 = x+ share2 = x + (delta * 2 / 3) = 1/3ximage009.jpg
效果恰好是成反比!!(网上很多人都误以为真成反比了!)
若有3个组件,权值分别为 1,2,3 设宽度为X,则计算如下:
Delta = x - 3x = -2x;
X1 = x + share1 = x + (-1/6 * 2x) = 2/3x
X2 = 1/3x
X3(上面两个用完空间了!)
所以效果还是:

image009.jpg?

接着算?权值为?2,3,4的结果如下:
Delta = -2x
X1 = x - 4/9x = 5/9x
........
效果就如下了:image010.png
总结:
1.要想让weight和你预想的效果一致,子组件的高度或者宽度需要设置为0dp,父容器(LinearLayout)要设置为fill_parent或者确定的值且不能为wrap_content,即mode 为 EXACTLY.

?

2.谨慎在 LinearLayout中使用 layout_weight(除非你使用正确), 这样所有子组件的尺寸会被计算两次,将影响性能.

?

3.Google的大神们为了赶版本,这个属性的逻辑有点混乱,文档不够详细,给俺们Android屌丝程序员们埋了好多坑!

?

4.关于网上的结论,什么权值大小和重要度成反比,子组件用wrap_content权值才会成正比等,都是错误的!
  相关解决方案