Pobieranie współrzędnych widoku względem układu głównego


Odpowiedzi:


138

Jest to jedno rozwiązanie, ale ponieważ interfejsy API zmieniają się w czasie i mogą istnieć inne sposoby, aby to zrobić, sprawdź pozostałe odpowiedzi. Jeden twierdzi, że jest szybszy, a inny twierdzi, że jest łatwiejszy.

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

Daj znać, jeśli to zadziała.

Powinien rekurencyjnie po prostu dodać górną i lewą pozycję z każdego kontenera nadrzędnego. Możesz również zaimplementować to za pomocą, Pointjeśli chcesz.


getRelativeLeft () to jest potrzebne dodanie rzutowania, ale kiedy dodaję (View) lub (button) ((Object) myView.getParent ()). getRelativeTop (), to również nie jest poprawne
pengwang

Zrobiłem coś bardzo podobnego, ale sprawdziłem widok katalogu głównego przez getId == R.id.myRootView.
fhucho

1
Log.i ("RelativeLeft", "" + getRelativeLeft (findViewById (R.id.tv))); Log.i ("RelativeTop", "" + getRelativeTop (findViewById (R.id.tv))); otrzymuję wszystko to 0; TextView w układzie wygląda następująco: <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

Takie uśmiechnięte podejście (ręczne obliczanie) zadziałało, więc zaakceptowałem tę odpowiedź.
fhucho

3
Android API już dostarcza współrzędnych względnych do katalogu głównego. spójrz tutaj stackoverflow.com/a/36740277/2008214
carlo.marinangeli

155

Interfejs API systemu Android już zapewnia metodę, aby to osiągnąć. Spróbuj tego:

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;

Oto doktor


16
To powinna być akceptowana odpowiedź. Brak możliwości przepełnienia stosu i błędów matematycznych. Dzięki!
GLee

Zgadzam się, to powinna być przyjęta odpowiedź - pozostało tylko 92 głosów pozytywnych.
oszołomiony

Chciałem znaleźć współrzędne widoku na pasku narzędzi. Jest to jedyna metoda, która działa konsekwentnie w przypadku systemu Android: fitSystemWindows i różne wersje API od 19 do 27. Dziękujemy! To jest właściwa odpowiedź.
David Ferrand,

Działało bez zarzutu
Rawa

Działało bardzo dobrze, wystarczy wspomnieć, że parentViewGroupmoże to być dowolny element nadrzędny w hierarchii widoków, więc działa również doskonale dla ScrollView.
Sira Lam

93

Użyj view.getLocationOnScreen(int[] location);(patrz Javadocs ). Odpowiedź znajduje się w tablicy liczb całkowitych (x = location[0]i y = location[1]).


13
Spowoduje to zwrócenie pozycji względem ekranu, a nie układu głównego działania.
fhucho

10
Istnieje również View.getLocationInWindow (int []), który zwraca pozycję widoku względem okna.
Rubicon

Czy możesz mi powiedzieć dokładnie, jak działa ta metoda. Zwraca void, jak to zrobić, otrzymujemy dane wyjściowe lub wartości x, y widoku na ekranie
user1106888

6
Aby uzyskać pozycję względem układu głównego, po prostu wywołaj metodę getLocationInWindow dla układu głównego i elementu i użyj mocy odejmowania. Jest to znacznie prostsze i prawdopodobnie szybsze niż zaakceptowana odpowiedź.
Blake Miller,

1
to jest tylko lokalizacja związana z ekranem. nie korzeń. czytaj tutaj w odniesieniu do roota: 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];

Najpierw otrzymuję układ główny, a następnie obliczam różnicę współrzędnych w stosunku do widoku.
Możesz także użyć getLocationOnScreen()zamiast getLocationInWindow().


3
jaki widok jest skalowany i obracany?
DKV

To jedyna odpowiedź, która mi odpowiada. To powinna zostać zaakceptowana odpowiedź
neoexpert

36

Nie ma potrzeby ręcznego obliczania.

Po prostu użyj getGlobalVisibleRect w następujący sposób:

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

Zauważ również, że dla współrzędnych środka, a nie czegoś takiego:

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

Możesz po prostu zrobić:

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

Patrząc na źródło Androida, wszystko getGlobalVisibleRectto robi, globalOffset.set(-mScrollX, -mScrollY);więc możesz po prostu uzyskać te wartości, getScollX/Yjeśli potrzebujesz tylko względnych współrzędnych.
Xander,

2
To powinna zostać zaakceptowana odpowiedź. getLocationOnScreen działa tak samo jak getGlobalVisibleRect. Ale getGlobalVisibleRect dostarcza nieco więcej informacji i nie ma potrzeby pracy z surowymi tablicami. Dlatego wybrałbym getGlobalVisibleRect. Użycie jest proste. Rect positionRect = new Rect (); view.getGlobablVisibleRect (positionRect); // x = positionRect.left // y = positionRect.top. zdrowie
JacksOnF1re

jeśli jakaś część dziecka jest na zewnątrz, co nie będzie brane pod uwagę w tym przypadku. jak rozwiązać taki przypadek?
DKV

Świetna odpowiedź! Dziękuję bardzo!
Rohit Kumar

8

Możesz użyć rozszerzenia `

view.getLocationOnScreen (int [] lokalizacja)

; `aby uzyskać poprawne położenie widoku.

Ale jest pewien haczyk, jeśli użyjesz go przed nadmuchaniem układu, uzyskasz niewłaściwą pozycję.

Rozwiązaniem tego problemu jest dodanie w ViewTreeObserverten sposób: -

Globalnie zadeklaruj tablicę do przechowywania pozycji xy widoku

 int[] img_coordinates = new int[2];

a następnie dodaj ViewTreeObserverswój układ nadrzędny, aby uzyskać wywołanie zwrotne dla inflacji układu i dopiero wtedy pobierz pozycję widoku, w przeciwnym razie otrzymasz błędne współrzędne 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);
                        }
                    }
            );

a następnie użyj go w ten sposób

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

3

Napisałem sobie dwie metody narzędziowe, które wydają się działać w większości warunków, obsługując przewijanie, tłumaczenie i skalowanie, ale nie rotację. Zrobiłem to po próbie użycia offsetDescendantRectToMyCoords () we frameworku, który miał niespójną dokładność. W niektórych przypadkach działało, ale w innych dawało złe wyniki.

„point” to tablica zmiennoprzecinkowa z dwoma elementami (współrzędne x & y), „przodek” to grupa widoku gdzieś powyżej „potomka” w hierarchii drzewa.

Najpierw metoda, która przechodzi od współrzędnych potomnych do przodków:

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

Dalej odwrotnie, od przodka do potomka:

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

O ile ktoś wciąż próbuje to rozgryźć. W ten sposób otrzymujesz środek X i Y elementu view.

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

1

Właśnie znalazłem odpowiedź tutaj

Mówi: Możliwe jest pobranie lokalizacji widoku przez wywołanie metod getLeft () i getTop (). Pierwsza z nich zwraca lewą, czyli X, współrzędną prostokąta reprezentującego widok. Ta ostatnia zwraca górną, czyli Y, współrzędną prostokąta reprezentującego widok. Obie te metody zwracają położenie widoku względem jego elementu nadrzędnego. Na przykład, gdy getLeft () zwraca 20, oznacza to, że widok znajduje się 20 pikseli na prawo od lewej krawędzi swojego bezpośredniego rodzica.

więc użyj:

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
Daje to lokalizację względem bezpośredniego elementu nadrzędnego widoku, a nie widoku głównego, który może być elementem nadrzędnym elementu nadrzędnego itp.
Rupert Rawnsley,

jaki widok jest skalowany i obracany?
DKV
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.