joy keeps flowin'

gravity和layout_gravity

xx
目次

背景 #

从开始写Android不断地有人告诉我,用gravity和layout_gravity控制View的位置,总是不明白两者有什么差别(中途明白过,又忘了😭),又是怎么实现的,最近想起来,赶紧查一查。

实现 #

首先gravity和layout_gravity都是View的一个属性,一直以为(没错,又是以为)类似height和width类似的,每个View都会有的,其实细想一下不是每个View都有。

gravity #

TextView是有gravity的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 解析属性
...
case com.android.internal.R.styleable.TextView_gravity:
    setGravity(a.getInt(attr, -1));
...
    
// 赋值
public void setGravity(int gravity) {
    ...
    mGravity = gravity;
    ...
}

// mGravity定义及默认值
private int mGravity = Gravity.TOP | Gravity.START;

// View中能起作用一定是跟测量有关,找到相关代码
public int getExtendedPaddingTop() {
    ...
    final int gravity = mGravity &  Gravity.VERTICAL_GRAVITY_MASK;
    if (gravity == Gravity.TOP) {
        return top;
    } else if (gravity == Gravity.BOTTOM) {
        return top + viewht - layoutht;
    } else { // (gravity == Gravity.CENTER_VERTICAL)
        return top + (viewht - layoutht) / 2;
    }
    ...
}

layout_gravity #

layout_gravity哪有呢,LinearLayout:

1
gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1);

LinearLayout中布局子View的代码。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void layoutVertical(int left, int top, int right, int bottom) {
...
int gravity = lp.gravity;
if (gravity < 0) {
    gravity = minorGravity;
}
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
    case Gravity.CENTER_HORIZONTAL:
        childLeft = paddingLeft + ((childSpace - childWidth) / 2) + lp.leftMargin - lp.rightMargin;
        break;

    case Gravity.RIGHT:
        childLeft = childRight - childWidth - lp.rightMargin;
        break;

    case Gravity.LEFT:
    default:
        childLeft = paddingLeft + lp.leftMargin;
        break;
}

...
}

恰好LinearLayout中也有用到gravity

1
2
3
4
5
// 取到gravity
index = a.getInt(com.android.internal.R.styleable.LinearLayout_gravity, -1);
if (index >= 0) {
    setGravity(index);
}

在设置baselineAligned为true时,gravity才会发挥作用。

Gravity #

Standard constants and tools for placing an object within a potentially larger container. 上面是源码中官方的注释。

可以发现代码中设置Gravity的地方用到了Gravity类,比较好理解Gravity类就是官方提供的一个工具类,让Gravity中每个属性代表的值统一。

总结 #

  1. gravity和layout_gravity和那个View没有关系,你想自定义View的时候实现也可以用;
  2. gravity是控制View内部的内容从哪里开始放置,一般用在View上;
  3. layout_gravity是控制子View怎么布局,一般用在ViewGroup上;
  4. 只要你想怎么实现都行。
标签:
Categories: