루트 레이아웃을 기준으로 뷰의 좌표 얻기


답변:


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

나는 매우 비슷한 것을했지만 getId == R.id.myRootView로 루트보기를 확인했습니다.
fhucho

1
Log.i ( "RelativeLeft", ""+ getRelativeLeft (findViewById (R.id.tv))); Log.i ( "RelativeTop", ""+ getRelativeTop (findViewById (R.id.tv))); 나는 모두 0이다. <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

이와 같은 비슷한 접근법 (수동 계산)이 저에게 효과적 이므로이 대답을 수락했습니다.
fhucho

3
안드로이드 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

동의 한 답변이어야한다고 동의합니다.
멍청한

툴바에서 뷰의 좌표를 찾고 싶었습니다. 이것은 android : fitsSystemWindows 및 19에서 27까지의 다양한 API 버전을 설명하기 위해 지속적으로 작동하는 한 가지 방법입니다. 감사합니다! 이것이 정답입니다.
David Ferrand

완벽하게 일함
Rawa

parentViewGroup작동했습니다.보기 계층의 부모가 될 수 있다고 말하고 싶기 때문에 ScrollView에서도 완벽하게 작동합니다.
Sira Lam

93

사용 view.getLocationOnScreen(int[] location);하십시오 ( Javadocs 참조 ). 답은 정수 배열에 있습니다 (x = location[0]및 y = location[1]).


13
이것은 활동의 루트 레이아웃이 아닌 화면에 대한 상대적 위치를 반환합니다.
fhucho

10
창을 기준으로 뷰의 위치를 ​​반환하는 View.getLocationInWindow (int [])도 있습니다.
Rubicon

이 방법이 어떻게 작동하는지 정확하게 알려주십시오. 화면에서 뷰의 출력 또는 x, y 값을 얻는 방법을 void로 반환합니다.
user1106888

6
루트 레이아웃과 관련된 위치를 얻으려면 루트 레이아웃과 요소에 대해 getLocationInWindow를 호출하고 빼기 기능을 사용하십시오. 허용 된 답변보다 훨씬 간단하고 빠릅니다.
Blake Miller

1
이것은 화면과 관련된 위치 일뿐입니다. 뿌리가 아닙니다. 루트와 관련하여 여기를 읽으십시오 : stackoverflow.com/a/36740277/2008214
carlo.marinangeli

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();

모든 안드로이드 소스를 보면 getGlobalVisibleRect않는 것은 globalOffset.set(-mScrollX, -mScrollY);당신이 단지와 그 값을 얻을 수 있도록 getScollX/Y당신은 단지 상대의 좌표가 필요합니다.
Xander

2
이 답변을 수락해야합니다. getLocationOnScreen은 getGlobalVisibleRect와 함께 작동합니다. 그러나 getGlobalVisibleRect는 조금 더 많은 정보를 제공하며 원시 배열로 작업 할 필요가 없습니다. 따라서 getGlobalVisibleRect를 사용합니다. 사용법은 간단합니다. 사각형 positionRect = new Rect (); view.getGlobablVisibleRect (positionRect); // x = positionRect.left // y = positionRect.top. 건배
JacksOnF1

아이의 일부가 외부에 있다면이 경우 고려하지 않을 것입니다. 그런 경우를 해결하는 방법?
DKV

좋은 대답입니다! 정말 고맙습니다!
Rohit Kumar

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 ()를 사용하려고 시도한 후에이 작업을 수행했습니다. 어떤 경우에는 효과가 있었지만 다른 결과에서는 잘못된 결과를 냈습니다.

"point"는 두 개의 요소 (x & y 좌표)를 가진 float 배열이고 "ancestor"는 트리 계층에서 "descendant"위의 뷰 그룹입니다.

먼저 자손 좌표에서 조상으로가는 방법 :

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;
}

2

누군가가 여전히 이것을 알아 내려고하려고하는 경우. 이것은의 중심 X와 Y를 얻는 방법 view입니다.

    int pos[] = new int[2];
    view.getLocationOnScreen(pos);
    int centerX = pos[0] + view.getMeasuredWidth() / 2;
    int centerY = pos[1] + view.getMeasuredHeight() / 2;

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

뷰의 크기와 회전은 무엇입니까?
DKV
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.