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

Posted

技术标签:

【中文标题】如何在自定义 Android 视图中检查重力标志?【英文标题】:How to check gravity flags in a custom Android View? 【发布时间】:2017-06-29 16:06:55 【问题描述】:

问题

我有一个自定义的 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 的检查仍然是真的!

为什么会这样?

我必须查看二进制值才能了解原因:

二进制:0001 0000Gravity.CENTER_VERTICAL:常量值:16 (0x00000010) 二进制:0101 0000Gravity.BOTTOM:常量值:80 (0x00000050)

因此,当我这样做时

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

我得到一个误报。

我该怎么办?

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

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

【问题讨论】:

【参考方案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_MASKHORIZONTAL_GRAVITY_MASK,这将帮助您找出应用了哪些重力。

【讨论】:

我完成了这个测试,我可以确认它有效。我错过了VERTICAL_GRAVITY_MASK【参考方案2】:

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

横轴重力

LEFTRIGHT 被称为绝对重力。也就是说,如果用户指定STARTEND 的相对重力,则根据情况,它是converted internally 到RIGHTLEFT 的绝对重力。

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。但是,应谨慎使用。应考虑从右到左的语言区域设置。

垂直轴重力

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

【讨论】:

I'm adding this to help myself , maan,这当然不仅适合你。不错,很详细!

以上是关于如何在自定义 Android 视图中检查重力标志?的主要内容,如果未能解决你的问题,请参考以下文章

在自定义视图中获取android attr

Android:在自定义视图上使用android绑定点击事件

Android:在自定义 Web 视图中检测并打开外部链接

在用户重新启动应用程序后,我应该如何在自定义列表视图中反映文本视图的增量值?

Android:需要在自定义适配器列表视图中保存复选框状态

滚动视图没有重力。如何使滚动视图内的内容为中心