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


답변:


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.