如何在自定义 Android 视图中检查重力标志?

How to check gravity flags in a custom Android View?

问题

我有一个自定义 Android 视图,我希望在其中设置用户重力以便在 onDraw 中布局内容。这是我在 onDraw:

中使用的简化版本
// check gravity
if ((mGravity & Gravity.CENTER_VERTICAL) == Gravity.CENTER_VERTICAL) {
    // draw the content centered vertically
} else if ((mGravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
    // draw the content at the bottom
}

其中 mGravity 是从 xml 属性 (like this) 中获得的。

如果我将重力设置为 Gravity.CENTER_VERTICAL 它工作正常。但是我惊奇的发现,如果我设置为Gravity.BOTTOMGravity.CENTER_VERTICAL的校验依然为真!

为什么会这样?

我不得不查看二进制值以了解原因:

因此,当我这样做时

mGravity = Gravity.BOTTOM;
(mGravity & Gravity.CENTER_VERTICAL) == Gravity.CENTER_VERTICAL
//  (0101 & 0001) == 0001

我误报了。

我该怎么办?

那么我该如何检查重力标志呢?

我可以做类似 if (mGravity == Gravity.CENTER_VERTICAL) 的事情,但那样我只会得到完全匹配。如果用户将重力设置为 center_vertical|right 之类的值,那么它将失败。

您可以检查 FrameLayout 如何放置其 children。特别是这段代码:

final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;

switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
    case Gravity.CENTER_HORIZONTAL:
        ...
    case Gravity.RIGHT:
        ...
    case Gravity.LEFT:
        ...
}

switch (verticalGravity) {
    case Gravity.TOP:
        ...
    case Gravity.CENTER_VERTICAL:
        ...
    case Gravity.BOTTOM:
        ...
}

Gravity class 中有掩码:VERTICAL_GRAVITY_MASKHORIZONTAL_GRAVITY_MASK 可以帮助您找出应用了哪些重力。

这是对@azizbekian 非常有用的解决方案的补充回答。我添加这个是为了帮助自己更全面地了解重力在幕后的工作原理。

横轴重力

LEFTRIGHT 被称为绝对重力。也就是说,如果用户指定 STARTEND 的相对重力,则它是 converted internallyRIGHTLEFT 的绝对重力,具体取决于情况。

0000 0001  CENTER_HORIZONTAL
0000 0011  LEFT
0000 0101  RIGHT
---------  
0000 0111  HORIZONTAL_GRAVITY_MASK

关于 STARTEND

的说明
1000 0000 0000 0000 0000 0011  START
0000 0000 0000 0000 0000 0011  LEFT
1000 0000 0000 0000 0000 0101  END
0000 0000 0000 0000 0000 0101  RIGHT
-----------------------------
0000 0000 0000 0000 0000 0111  HORIZONTAL_GRAVITY_MASK

正如您在此处看到的,STARTLEFT 仅存在一点点差异。 ENDRIGHT 相同。因此,如果您直接在 STARTEND 上使用 HORIZONTAL_GRAVITY_MASK,它们将分别默认为 LEFTRIGHT。但是,应谨慎使用。 Right-to-left 应考虑语言环境。

垂直轴重力

y 轴重力从 x 轴(水平)重力偏移超过 4 位。

0001 0000  CENTER_VERTICAL
0011 0000  TOP
0101 0000  BOTTOM
---------
0111 0000  VERTICAL_GRAVITY_MASK

双轴

请注意 CENTERCENTER_VERTICALCENTER_HORIZONTAL 的组合。因此,您也可以使用其中一种重力蒙版进行转换。

0000 0001  CENTER_HORIZONTAL
0001 0000  CENTER_VERTICAL
0001 0001  CENTER
---------
0000 0111  HORIZONTAL_GRAVITY_MASK
0111 0000  VERTICAL_GRAVITY_MASK

位数学

使用位或运算符 (|) 组合水平和垂直重力。

示例:

int myGravity = Gravity.RIGHT | Gravity.BOTTOM;

0000 0101  RIGHT
0101 0000  BOTTOM
---------
0101 0101  myGravity

将位与运算符 (&) 与重力掩码之一结合使用,以隔离水平或垂直重力。

例子

int verticalGravity = myGravity & Gravity.VERTICAL_GRAVITY_MASK;
if (verticalGravity == Gravity.BOTTOM) ...

0101 0101  myGravity
0111 0000  VERTICAL_GRAVITY_MASK
---------
0101 0000  verticalGravity
0101 0000  BOTTOM