获取相对于根布局的View坐标


Answers:


138

这是一个解决方案,尽管由于API会随着时间而变化,并且可能还有其他实现方法,所以请确保检查其他答案。一个声称更快,另一个声称更容易。

private int getRelativeLeft(View myView) {
    if (myView.getParent() == myView.getRootView())
        return myView.getLeft();
    else
        return myView.getLeft() + getRelativeLeft((View) myView.getParent());
}

private int getRelativeTop(View myView) {
    if (myView.getParent() == myView.getRootView())
        return myView.getTop();
    else
        return myView.getTop() + getRelativeTop((View) myView.getParent());
}

让我知道是否可行。

它应该以递归方式添加每个父容器的顶部和左侧位置。如果需要,也可以使用实现它Point


getRelativeLeft()这需要添加演员表,但是当我添加(View)或(button)((Object)myView.getParent())。getRelativeTop()时,它也不对
pengwang 2010年

我做了一些非常相似的事情,但是我通过getId == R.id.myRootView检查了根视图。
fhucho

1
Log.i(“ RelativeLeft”,“” + getRelativeLeft(findViewById(R.id.tv)));; Log.i(“ RelativeTop”,“” + getRelativeTop(findViewById(R.id.tv)));; 我得到的都是0;布局中的textView如下所示:<TextView android:layout_width =“ fill_parent” android:layout_height =“ wrap_content” android:text =“ @ string / hello” android:id =“ @ + id / tv” android:layout_marginBottom =“ 69dip” android:layout_marginLeft =“ 69dip” />
pengwang 2010年

像这样的类似方法(手动计算)对我有用,因此我接受了这个答案。
富乔2012年

3
android api已经提供了到根的相对坐标。在这里看stackoverflow.com/a/36740277/2008214
carlo.marinangeli

155

Android API已经提供了一种实现此目的的方法。试试这个:

Rect offsetViewBounds = new Rect();
//returns the visible bounds
childView.getDrawingRect(offsetViewBounds);
// calculates the relative coordinates to the parent
parentViewGroup.offsetDescendantRectToMyCoords(childView, offsetViewBounds); 

int relativeTop = offsetViewBounds.top;
int relativeLeft = offsetViewBounds.left;

这是文档


16
这应该是公认的答案。没有堆栈溢出的可能性,也没有数学错误的可能性。谢谢!
GLee

我同意,这应该是公认的答案-只有92票赞成。
昏昏欲睡的

我想在工具栏中找到视图的坐标。这是一种始终有效地解决android:fitsSystemWindows和19至27的各种API版本的方法。谢谢!这是正确的答案。
大卫·费朗

完美无瑕地工作
Rawa '18

工作得很好,只想提到它parentViewGroup可以是视图层次结构中的任何父级,因此它也非常适合ScrollView。
西拉林'18

93

请使用view.getLocationOnScreen(int[] location);(请参阅Javadocs)。答案在整数数组(x = location[0]和y = location[1])中。


13
这将返回相对于屏幕的位置,而不是“活动”的根布局。
fhucho 2012年

10
还有View.getLocationInWindow(int []),它返回视图相对于窗口的位置。
Rubicon

您能否确切告诉我这种方法的工作原理。它返回一个空值,我们如何获取屏幕上视图的输出或x,y值
user1106888 2012年

6
要获得相对于根布局的位置,只需为根布局和元素调用getLocationInWindow,然后使用减法即可。它比公认的答案要简单得多,而且可能更快。
Blake Miller

1
这只是与屏幕相关的位置。不是根。请阅读此处以了解相对于根的信息:stackoverflow.com/a/36740277/2008214
carlo.marinangeli,2016年

36
View rootLayout = view.getRootView().findViewById(android.R.id.content);

int[] viewLocation = new int[2]; 
view.getLocationInWindow(viewLocation);

int[] rootLocation = new int[2];
rootLayout.getLocationInWindow(rootLocation);

int relativeLeft = viewLocation[0] - rootLocation[0];
int relativeTop  = viewLocation[1] - rootLocation[1];

首先,我得到根布局,然后计算与视图的坐标差。
您也可以使用getLocationOnScreen()代替getLocationInWindow()


3
视图是缩放和旋转的是什么?
DKV

这是唯一对我有用的答案。这应该被接受的答案
neoexpert

36

无需手动计算。

像这样使用getGlobalVisibleRect

Rect myViewRect = new Rect();
myView.getGlobalVisibleRect(myViewRect);
float x = myViewRect.left;
float y = myViewRect.top;

另请注意,对于中心坐标,而不是类似以下内容:

...
float two = (float) 2
float cx = myViewRect.left + myView.getWidth() / two;
float cy = myViewRect.top + myView.getHeight() / two;

您可以这样做:

float cx = myViewRect.exactCenterX();
float cy = myViewRect.exactCenterY();

查看android源代码的全部getGlobalVisibleRect操作是, globalOffset.set(-mScrollX, -mScrollY);因此getScollX/Y如果您只需要相对coodinates,就可以获取这些值。
Xander 2013年

2
这应该被接受。getLocationOnScreen和getGlobalVisibleRect一样有效。但是getGlobalVisibleRect提供了更多信息,并且不需要使用原始数组。因此,我将使用getGlobalVisibleRect。用法很简单。矩形positionRect = new Rect(); view.getGlobablVisibleRect(positionRect); // x = positionRect.left // y = positionRect.top。欢呼声
JacksOnF1re

如果孩子的某个部分在外面,则在这种情况下不会考虑。如何解决这种情况?
DKV

好答案!非常感谢!
罗希特·库玛

8

您可以使用`

view.getLocationOnScreen(int []位置)

;`以正确获取视图的位置。

但有一个捕获如果你使用它之前的布局已经膨胀,你会得到错误的位置。

解决此问题的方法是这样添加的ViewTreeObserver:-

全局声明数组以存储视图的xy位置

 int[] img_coordinates = new int[2];

然后添加ViewTreeObserver您的父布局以获取布局膨胀的回调,然后仅获取视图位置,否则您将得到错误的xy坐标

  // set a global layout listener which will be called when the layout pass is completed and the view is drawn
            parentViewGroup.getViewTreeObserver().addOnGlobalLayoutListener(
                    new ViewTreeObserver.OnGlobalLayoutListener() {
                        public void onGlobalLayout() {
                            //Remove the listener before proceeding
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                                parentViewGroup.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                            } else {
                                parentViewGroup.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                            }

                            // measure your views here
                            fab.getLocationOnScreen(img_coordinates);
                        }
                    }
            );

然后像这样使用它

xposition = img_coordinates[0];
yposition =  img_coordinates[1];

3

我为自己编写了两个似乎在大多数情况下都可以使用的实用程序方法,即处理滚动,平移和缩放,但不适用于旋转。我在尝试在框架中使用offsetDescendantRectToMyCoords()后执行了此操作,该框架的准确性不一致。它在某些情况下有效,但在其他情况下却给出错误的结果。

“点”是具有两个元素(x和y坐标)的浮点数组,“祖先”是树层次结构中“后代”上方某处的视图组。

首先是从后代坐标到祖先的方法:

public static void transformToAncestor(float[] point, final View ancestor, final View descendant) {
    final float scrollX = descendant.getScrollX();
    final float scrollY = descendant.getScrollY();
    final float left = descendant.getLeft();
    final float top = descendant.getTop();
    final float px = descendant.getPivotX();
    final float py = descendant.getPivotY();
    final float tx = descendant.getTranslationX();
    final float ty = descendant.getTranslationY();
    final float sx = descendant.getScaleX();
    final float sy = descendant.getScaleY();

    point[0] = left + px + (point[0] - px) * sx + tx - scrollX;
    point[1] = top + py + (point[1] - py) * sy + ty - scrollY;

    ViewParent parent = descendant.getParent();
    if (descendant != ancestor && parent != ancestor && parent instanceof View) {
        transformToAncestor(point, ancestor, (View) parent);
    }
}

接下来是相反的,从祖先到后代:

public static void transformToDescendant(float[] point, final View ancestor, final View descendant) {
    ViewParent parent = descendant.getParent();
    if (descendant != ancestor && parent != ancestor && parent instanceof View) {
        transformToDescendant(point, ancestor, (View) parent);
    }

    final float scrollX = descendant.getScrollX();
    final float scrollY = descendant.getScrollY();
    final float left = descendant.getLeft();
    final float top = descendant.getTop();
    final float px = descendant.getPivotX();
    final float py = descendant.getPivotY();
    final float tx = descendant.getTranslationX();
    final float ty = descendant.getTranslationY();
    final float sx = descendant.getScaleX();
    final float sy = descendant.getScaleY();

    point[0] = px + (point[0] + scrollX - left - tx - px) / sx;
    point[1] = py + (point[1] + scrollY - top - ty - py) / sy;
}


1

我刚刚在这里找到答案

它说:可以通过调用方法getLeft()和getTop()来检索视图的位置。前者返回表示视图的矩形的左坐标或X坐标。后者返回代表视图的矩形的顶部或Y坐标。这些方法都返回视图相对于其父视图的位置。例如,当getLeft()返回20时,这意味着该视图位于其直接父级的左边缘右侧20像素处。

因此使用:

view.getLeft(); // to get the location of X from left to right
view.getRight()+; // to get the location of Y from right to left

1
这给出了相对于视图的直接父级而不是根视图的位置,后者可能是父级的父级,等等……
Rupert Rawnsley 2015年

视图是缩放和旋转的是什么?
DKV
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.