Abrufen der View-Koordinaten relativ zum Stammlayout

142

Kann ich die x- und y-Position einer Ansicht relativ zum Stammlayout meiner Aktivität in Android abrufen?

fhucho
quelle

Antworten:

138

Dies ist eine Lösung. Da sich APIs im Laufe der Zeit ändern und es möglicherweise andere Möglichkeiten gibt, sollten Sie die anderen Antworten überprüfen. Einer behauptet, schneller zu sein, und ein anderer behauptet, einfacher zu sein.

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

Lassen Sie mich wissen, ob das funktioniert.

Es sollte rekursiv nur die obere und linke Position von jedem übergeordneten Container hinzugefügt werden. Sie können es auch mit einem implementieren, Pointwenn Sie möchten.

Ramblinjan
quelle
getRelativeLeft () dies muss hinzugefügt werden, aber wenn ich (View) oder (button) ((Object) myView.getParent ()). getRelativeTop () hinzufüge, ist es auch nicht richtig
pengwang
Ich habe etwas sehr ähnliches gemacht, aber ich habe mit getId == R.id.myRootView nach der Stammansicht gesucht.
Fhucho
1
Log.i ("RelativeLeft", "" + getRelativeLeft (findViewById (R.id.tv))); Log.i ("RelativeTop", "" + getRelativeTop (findViewById (R.id.tv))); Ich bekomme alles ist 0; textView im Layout lautet wie folgt: <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
Ein solcher Smiliar-Ansatz (manuelle Berechnung) hat bei mir funktioniert, daher habe ich diese Antwort akzeptiert.
Fhucho
3
Die Android-API liefert bereits die relative Koordinate zur Wurzel. Schauen Sie hier stackoverflow.com/a/36740277/2008214
carlo.marinangeli
155

Die Android-API bietet bereits eine Methode, um dies zu erreichen. Versuche dies:

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;

Hier ist das Dokument

carlo.marinangeli
quelle
16
Dies sollte die akzeptierte Antwort sein. Keine Möglichkeit eines Stapelüberlaufs und keine Möglichkeit von Rechenfehlern. Vielen Dank!
GLee
Ich stimme zu, dies sollte die akzeptierte Antwort sein - nur noch 92 Up-Votes.
benommen
Ich wollte die Koordinaten einer Ansicht in der Symbolleiste finden. Dies ist die einzige Methode, die konsistent funktioniert, um Android zu berücksichtigen: fitSystemWindows und verschiedene API-Versionen von 19 bis 27. Also danke! Dies ist die richtige Antwort.
David Ferrand
Funktionierte einwandfrei
Rawa
Hat sehr gut parentViewGroupfunktioniert , möchte nur erwähnen, dass es sich um ein beliebiges übergeordnetes Element in der Ansichtshierarchie handeln kann, sodass es auch für ScrollView perfekt funktioniert.
Sira Lam
93

Bitte benutzen Sie view.getLocationOnScreen(int[] location);(siehe Javadocs ). Die Antwort liegt im Integer-Array (x = location[0]und y = location[1]).

BinaryTofu
quelle
13
Dadurch wird die Position relativ zum Bildschirm und nicht zum Stammlayout der Aktivität zurückgegeben.
Fhucho
10
Es gibt auch View.getLocationInWindow (int []), das die Position der Ansicht relativ zum Fenster zurückgibt.
Rubicon
Können Sie mir bitte genau sagen, wie diese Methode funktioniert? Es gibt eine Leere zurück, wie wir die Ausgabe oder x, y-Werte einer Ansicht auf dem Bildschirm erhalten
user1106888
6
Um die Position relativ zum Root-Layout zu ermitteln, rufen Sie einfach getLocationInWindow für das Root-Layout und das Element auf und verwenden Sie die Subtraktionskraft. Es ist viel einfacher und wahrscheinlich schneller als die akzeptierte Antwort.
Blake Miller
1
Dies ist nur der Ort, der sich auf den Bildschirm bezieht. nicht die Wurzel. Lesen Sie hier für relativ zu root: 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];

Zuerst erhalte ich das Root-Layout und berechne dann die Koordinatendifferenz mit der Ansicht.
Sie können auch die getLocationOnScreen()anstelle von verwenden getLocationInWindow().

Kerrmiter
quelle
3
Was ist die Ansicht ist skaliert und gedreht?
DKV
Dies ist die einzige Antwort, die für mich funktioniert. Diese Antwort sollte akzeptiert werden
neoexpert
36

Sie müssen es nicht manuell berechnen.

Verwenden Sie einfach getGlobalVisibleRect wie folgt :

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

Beachten Sie auch, dass für die Mittelkoordinaten eher als:

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

Sie können einfach tun:

float cx = myViewRect.exactCenterX();
float cy = myViewRect.exactCenterY();
Hoch
quelle
Alle auf der Android Quelle der Suche getGlobalVisibleRecttun , ist , globalOffset.set(-mScrollX, -mScrollY);so dass Sie nur diese Werte mit bekommen könnten , getScollX/Ywenn Sie brauchen , um den relativen von Koordinaten.
Xander
2
Dies sollte als Antwort akzeptiert werden. getLocationOnScreen funktioniert genauso gut wie getGlobalVisibleRect. GetGlobalVisibleRect bietet jedoch etwas mehr Informationen und es besteht keine Notwendigkeit, mit Raw-Arrays zu arbeiten. Ich würde daher mit getGlobalVisibleRect gehen. Die Verwendung ist einfach. Rect positionRect = new Rect (); view.getGlobablVisibleRect (positionRect); // x = positionRect.left // y = positionRect.top. prost
JacksOnF1re
Wenn sich ein Teil des Kindes außerhalb befindet, wird dies in diesem Fall nicht berücksichtigt. Wie kann man einen solchen Fall lösen?
DKV
Gute Antwort! Ich danke dir sehr!
Rohit Kumar
8

Sie können `verwenden

view.getLocationOnScreen (int [] location)

; `um den Ort Ihrer Ansicht korrekt zu ermitteln.

Aber es gibt einen Haken, wenn Sie es verwenden, bevor das Layout aufgeblasen wurde, erhalten Sie eine falsche Position.

Die Lösung für dieses Problem besteht darin, Folgendes hinzuzufügen ViewTreeObserver: -

Deklarieren Sie das Array global, um die xy-Position Ihrer Ansicht zu speichern

 int[] img_coordinates = new int[2];

Fügen ViewTreeObserverSie dann Ihr übergeordnetes Layout hinzu, um einen Rückruf für das Aufblasen des Layouts zu erhalten, und rufen Sie erst dann die Position der Ansicht ab, da sonst falsche xy-Koordinaten angezeigt werden

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

und dann benutze es so

xposition = img_coordinates[0];
yposition =  img_coordinates[1];
Hitesh Sahu
quelle
3

Ich habe mir zwei Dienstprogrammmethoden geschrieben, die unter den meisten Bedingungen zu funktionieren scheinen: Scrollen, Übersetzen und Skalieren, aber nicht Drehen. Ich habe dies getan, nachdem ich versucht hatte, offsetDescendantRectToMyCoords () im Framework zu verwenden, das eine inkonsistente Genauigkeit aufwies. In einigen Fällen funktionierte es, in anderen gab es falsche Ergebnisse.

"point" ist ein Float-Array mit zwei Elementen (den x & y-Koordinaten). "ancestor" ist eine Ansichtsgruppe irgendwo über dem "Nachkommen" in der Baumhierarchie.

Zuerst eine Methode, die von den Nachkommenkoordinaten zum Vorfahren geht:

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

Als nächstes die Umkehrung vom Vorfahren zum Nachkommen:

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;
}
Alexander Hugestrand
quelle
2

Falls jemand immer noch versucht, dies herauszufinden. So erhalten Sie das Zentrum X und Y des view.

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

Ich habe gerade die Antwort hier gefunden

Es heißt: Es ist möglich, den Speicherort einer Ansicht durch Aufrufen der Methoden getLeft () und getTop () abzurufen. Ersteres gibt die linke oder X-Koordinate des Rechtecks ​​zurück, das die Ansicht darstellt. Letzteres gibt die obere oder Y-Koordinate des Rechtecks ​​zurück, das die Ansicht darstellt. Diese Methoden geben beide die Position der Ansicht relativ zu ihrer übergeordneten Ansicht zurück. Wenn getLeft () beispielsweise 20 zurückgibt, bedeutet dies, dass sich die Ansicht 20 Pixel rechts vom linken Rand ihres direkten übergeordneten Elements befindet.

Verwenden Sie also:

view.getLeft(); // to get the location of X from left to right
view.getRight()+; // to get the location of Y from right to left
donmj
quelle
1
Dies gibt die Position relativ zum unmittelbaren übergeordneten Element der Ansicht an, nicht zur Stammansicht, die das übergeordnete Element des übergeordneten Elements usw. sein könnte.
Rupert Rawnsley
Was ist die Ansicht ist skaliert und gedreht?
DKV