在实际android app开发中避免不了美工挑剔的各种细节设计,比如这个线框距离上方多了几像素,输入框里的文字距离边框太近了等等繁琐但是影响美观的细节要求。那么究竟这几个需要注意的地方是哪里呢?下面我们来详细分析一下:
- margin:即外边距。两个组件间的间距,不属于任何组件,是“多余”的部分。对其他组件设置背景对margin区域部分无效。
- padding:即内边距。围成的区域仍属于原来的组件,所以给我们给父控件设置背景会发现背景充满了整个区域。
- weight::即权值。在布局的时候动态给组件设置width 和 height的大小。
在我开始使用过程weight时,非常不理解weight这个属性。将vertical 或者 horizontal 方向上需要延伸的设置其他小为fill_parent,然后设置权值,但是结果却并不是我们直观想想的那样,第一个权值为1,第二个权值为2,所以宽度之比为1:2。但结果却并不是我们想想的那样,实际上是2:1。
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="50dp"
android:background="#000"
android:orientation="horizontal">
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="width=fill_parent: weight=1"
android:gravity="center"
android:background="#555"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="2"
android:text="weight=2"
android:gravity="center"
android:background="#eee"/>
</LinearLayout>
但是呢,看下面一段代码:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="50dp"
android:background="#000"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="width=0dp: weight=1"
android:gravity="center"
android:background="#555"/>
<TextView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="2"
android:text="weight=2"
android:gravity="center"
android:background="#eee"/>
</LinearLayout>
将需要延伸的设置其他小为0dp,权值仍设置为第一个权值为1,第二个权值为2,但是实际宽度结果却是2:1。

怎样解答这个疑问呢?其实这纯粹是个数学问题:
在水平方向上有两个TextView,每个的宽度都是fill_parent,记为 x。那么理论上LinearLayout的宽度为2x,但是实际手机屏幕只有x,那么还少了一个x的宽度。所以不仅有限的手机屏幕会按照权值进行分配,那缺失的x宽度也会按照权值进行分配,即:
left_weight = x +(-x)*1/3 = 2x/3
right_weight = x + (-x)*2/3 = x/3
left_weight : right_weight = 2 : 1
同理,当设置宽度为0dp的时候,只不过此时剩余空间为x,计算方法为:
对于多个组件按照权值进行分配也是按照这种方法进行计算的。但是如果计算过程中有负值,将会从左到有(水平布局),从上到下(垂直布局)进行填充,直到屏幕填充满为止,比如看下面一段代码:left_weight = 0 + (x)*1/3 = x/3
right_weight = 0 + (x)*2/3 = 2x/3
left_weight : right_weight = 1:2
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="50dp"
android:orientation="horizontal" >
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:background="#aa0000"
android:text="r" />
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="2"
android:background="#00aa00"
android:text="g" />
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="4"
android:background="#0000aa"
android:text="b" />
</LinearLayout>

按上面的方法进行计算:
w1 = x + (-2x) / 7 = 5x/7
w2 = x + 2*(-2x)/7 = 3x/7
w3 = x + 4*(-2x)/7 = -x/7
此时计算的权值比:5/7:3/7:(-1/7)。但是屏幕填充的过程从左到右,即为5:2:0。第二个组件有1/3没有显示出来,第三个组件完全没有显示出来。
其实layout_weight 是父容器处理的,因为父容器根据layout_weight的大小和layout_width(layout_height)来进行实际尺寸的分配,而与TextView联系不大(但是会影响显示的样式)。另外,layout_weight只对Linearlayout及其子类有效,对于其他组件是无效的。
如果,我们把margin 和 padding 和weight一起使用,那么margin,padding,weight 会按照那个顺序来了?
margin理论上是组件间的间距,会不会先把margin的位置留出来,然后按照权值的大小进行分配宽高?还是把margin 和 padding加在组件之中分配宽高?答案是后者。padding加入组件之中再计算很容易理解,但是margin呢?
我们先来分析一下:假如我们来做,我们把margin单独来计算,然后按权值进行分配宽高,那么我们需要额外的结构来存储页面的树形结构从而来计算所有的margin值,然后再按权值分配大小。而如果我们把margin也当做组件内部属性来做的话,则不需要额外的空间来计算,仅仅是当做“padding”的处理方法即可,在画组件的时候才留空间出来即可。实际上,查看源码也是按照后一种方式处理的。
其实将margin当做组件内来计算个人觉得除了在计算中提高性能之外不是一个好方案,因为按照面向对象的思想,margin并非是属于组件自身的,而是属于和组件是同一个等级的组件,不过这个同等级的组件太简单了,不如归并到基本组件之中当做组件的属性从而来提高复用性和效率。在这个程度上来考虑未尝不是一种很好的设计思路。