2

MotionEvent.getRawX/.getRawY 返回绝对坐标(即基于整个屏幕)。但是接收到 MotionEvent 的视图可能(可能是)另一个视图的子视图,它本身可能在屏幕上的某个偏移处,等等。

特别是,我现在正在试验一个基本应用程序,Android 菜单/工具栏(带有时钟等)在屏幕顶部可见。当我调用 .getRawX/.getRawY 时,我得到了整个显示器的准确 X/Y 坐标 - 但是如果可以有菜单,或者如果 (grand)父视图本身比屏幕小并偏离其边缘?

现在,如果我使用 .getRawX/.getRawY 的返回值重新定位视图,它们可以工作,但视图会“跳”到屏幕顶部菜单的高度,因为“绝对”Y由于其上方的菜单,该值本质上增加了父视图的垂直偏移量。因此需要有一个通用的案例方法来确定父视图在屏幕的绝对坐标中的位置,以便在用于重新定位相关视图之前可以调整原始 X/Y 值。

我不想费心发布代码,因为它基本上是这个网站和许多其他网站上“通过触摸移动视图”的所有其他示例的重复。我没有要查找的错误...我正在寻找将 MotionEvent 的绝对坐标与任何未以 100% 全屏运行的应用程序的相对坐标相关联的方法。

4

2 回答 2

3

您可以使用 View.getLocationOnScreen() 来查找视图的绝对屏幕坐标,然后在屏幕坐标中计算所有内容和/或您自己基于此坐标进行转换。

于 2013-05-22T03:45:19.053 回答
0

根据 GreyBeardedGeek 关于 .getLocationOnScreen 的提示,这里有一个示例 onTouchListener,它可以用手指移动 View。它成功地容纳了菜单、工具栏、状态栏、不在任一轴上的父视图等。我想我会分享这个,因为我已经看到了很多关于该主题的帖子,但没有一个真正完全回答了这个问题。它是故意罗嗦的,并且使用了比必要更多的当地人来帮助说明正在发生的事情。

public boolean  onTouch(View v,MotionEvent event) {

    boolean bExitValue = true;
    int             iOffsetX;
    int             iOffsetY;
    int             iNewX;
    int             iNewY;
    int[]           aLocation = new int [ 2 ];
    int             iAction;

    iAction = event.getActionMasked();

    if (MotionEvent.ACTION_MOVE == iAction) {
        v.getLocationOnScreen(aLocation);                   // get absolute physical location of this View
        iOffsetX =  (aLocation [ 0 ] - (int) v.getX());     // subtract out this View's relative location within its parent View...
        iOffsetY =  (aLocation [ 1 ] - (int) v.getY());     // ...yielding the offsets that convert getRawX/Y's coords to setX/Y's coords

        iNewX = (int) event.getRawX();                      // get absolute physical coords of this touch
        iNewY = (int) event.getRawY();
        iNewX -= iOffsetX;                                  // remove parent View's screen offset (calc'd above)
        iNewY -= iOffsetY;
        iNewX -= iRelX;                                     // remove stored touch offset
        iNewY -= iRelY;
        v.setX(iNewX);                                      // finally, move View to new coords (relative to its parent View)
        v.setY(iNewY);
    }

    else if (MotionEvent.ACTION_DOWN == iAction) {
        iRelX = (int) event.getX();                         // preserve offset of this touch within the View
        iRelY = (int) event.getY();
    }

    else {
        bExitValue = false;
    }

    return(bExitValue);

}

关键点:

  • 必须在您的 ACTION_DOWN 处理程序中捕获触摸在视图中的偏移量并将其存储到类级字段(即静态变量)。您希望保留此偏移量,以便 View 保持其与手指的位置关系,但您不能只使用每个 ACTION_MOVE 抓取一个新副本,因为它们将精确地偏移手指移动并且不会发生移动。

  • View.getLocationOnScreen 返回绝对坐标,而 View.getX/Y 返回相对于父 View 的坐标。这就是处理非全屏父视图的方式。这两个坐标对之间的区别在于将 MotionEvent.getRawX/Y 的绝对坐标转换为 View.setX/Y 所需的父视图相对坐标的偏移量。

非常感谢 GreyBeardedGeek 识别 View.getLocationOnScreen。希望这段代码摘录对其他人有所帮助。谢谢!

于 2013-05-22T23:14:11.897 回答