Подтвердить что ты не робот

Как проверить флаги гравитации в пользовательском представлении Android?

Проблема

У меня есть пользовательский вид 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 (как это).

Если я устанавливаю значение силы тяжести на Gravity.CENTER_VERTICAL, он работает нормально. Но я с удивлением обнаружил, что если я установил его в Gravity.BOTTOM, проверка Gravity.CENTER_VERTICAL по-прежнему верна!

Почему это происходит?

Мне пришлось посмотреть двоичные значения, чтобы понять, почему:

  • Binary: 0001 0000, Gravity.CENTER_VERTICAL: Постоянное значение: 16 (0x00000010)
  • Binary: 0101 0000, Gravity.BOTTOM: Постоянное значение: 80 (0x00000050)

Таким образом, когда я делаю

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

Я получаю ложное срабатывание.

Что мне делать?

Итак, как я могу проверить флаги гравитации?

Я мог бы сделать что-то вроде if (mGravity == Gravity.CENTER_VERTICAL), но тогда я бы получил только точное совпадение. Если пользователь установил гравитацию на что-то вроде center_vertical|right, тогда он потерпит неудачу.

4b9b3361

Ответ 1

Вы можете узнать, как FrameLayout закладывает своих детей. В частности, этот код:

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 есть маски: VERTICAL_GRAVITY_MASK, HORIZONTAL_GRAVITY_MASK, которые помогут вам определить, какие гравитации были применены.

Ответ 2

Это дополнительный ответ на полезное решение @azizbekian. Я добавляю это, чтобы помочь себе более полно понять, как гравитация работает за кулисами.

Горизонтальная ось тяжести

LEFT и RIGHT известны как абсолютная сила тяжести. То есть, если пользователь указывает относительную плотность START или END, то она преобразуется внутренне в абсолютный вес RIGHT или LEFT в зависимости от ситуации.

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

Заметка о START и END

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

Как вы можете видеть здесь, START и LEFT отличаются только одним битом. То же самое для END и RIGHT. Таким образом, если вы используете HORIZONTAL_GRAVITY_MASK непосредственно на START и END, по умолчанию они будут LEFT и RIGHT соответственно. Однако это следует использовать с осторожностью. Необходимо учитывать правовые локальные языки.

Гравировка по вертикальной оси

Тягость оси Y смещается на 4 бита от оси х (горизонтальная).

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

Обе оси

Обратите внимание, что CENTER представляет собой комбинацию CENTER_VERTICAL и CENTER_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