Ottenere le coordinate di View relative al layout di root


Risposte:


138

Questa è una soluzione, anche se poiché le API cambiano nel tempo e potrebbero esserci altri modi per farlo, assicurati di controllare le altre risposte. Uno afferma di essere più veloce e un altro afferma di essere più semplice.

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

Fammi sapere se funziona.

Dovrebbe ricorsivamente aggiungere le posizioni superiore e sinistra di ciascun contenitore principale. Potresti anche implementarlo con un Pointse lo desideri.


getRelativeLeft () è necessario aggiungere cast, ma quando aggiungo (Visualizza) o (pulsante) ((Oggetto) myView.getParent ()). getRelativeTop (), non è nemmeno corretto
pengwang

Ho fatto qualcosa di molto simile, ma ho controllato la vista radice da getId == R.id.myRootView.
fhucho,

1
Log.i ("RelativeLeft", "" + getRelativeLeft (findViewById (R.id.tv))); Log.i ("RelativeTop", "" + getRelativeTop (findViewById (R.id.tv))); ottengo tutto è 0; textView nel layout è il seguente <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

Un approccio simile a questo (calcolandolo manualmente) ha funzionato per me, quindi ho accettato questa risposta.
fhucho,

3
l'api android fornisce già le coordinate relative alla radice. guarda qui stackoverflow.com/a/36740277/2008214
carlo.marinangeli

155

L'API Android fornisce già un metodo per raggiungere questo obiettivo. Prova questo:

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;

Ecco il documento


16
Questa dovrebbe essere la risposta accettata. Nessuna possibilità di overflow dello stack e nessuna possibilità di errori matematici. Grazie!
GLee,

Sono d'accordo, questa dovrebbe essere la risposta accettata - solo 92 voti positivi.
stordito il

Volevo trovare le coordinate di una vista nella barra degli strumenti. Questo è l'unico metodo che funziona costantemente per tenere conto di Android: fitsSystemWindows e varie versioni di API dal 19 al 27. Quindi grazie! Questa è la risposta esatta.
David Ferrand,

Ha funzionato alla perfezione
Rawa il

Ha funzionato molto bene, voglio solo menzionare che parentViewGrouppuò essere qualsiasi genitore nella gerarchia della vista, quindi funziona perfettamente anche con ScrollView.
Sira Lam,

93

Si prega di utilizzare view.getLocationOnScreen(int[] location);(consultare Javadocs ). La risposta è nell'array intero (x = location[0]e y = location[1]).


13
Ciò restituisce la posizione relativa allo schermo e non al layout radice dell'Attività.
fhucho,

10
Esiste anche View.getLocationInWindow (int []) che restituisce la posizione della vista rispetto alla finestra.
Rubicon,

Potete per favore dirmi esattamente come funziona questo metodo. Restituisce un vuoto come fare otteniamo l'output o i valori x, y di una vista sullo schermo
user1106888

6
Per ottenere la posizione relativa al layout di root, basta chiamare getLocationInWindow per il layout di root e l'elemento, e usare il potere della sottrazione. È molto più semplice e probabilmente più veloce della risposta accettata.
Blake Miller,

1
questa è solo la posizione relativa allo schermo. non il root. Leggi qui per relativo alla radice: 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];

Per prima cosa ottengo il layout di root, quindi calcolo la differenza di coordinate con la vista.
Puoi anche usare getLocationOnScreen()invece di getLocationInWindow().


3
qual è la vista viene ridimensionata e ruotata?
DKV,

Questa è l'unica risposta che funziona per me. Questa dovrebbe essere una risposta accettata
neoexpert

36

Non è necessario calcolarlo manualmente.

Usa getGlobalVisibleRect in questo modo:

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

Nota anche che per le coordinate centrali, piuttosto che qualcosa di simile:

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

Puoi semplicemente fare:

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

Guardando la fonte Android tutto getGlobalVisibleRectciò che fa è in globalOffset.set(-mScrollX, -mScrollY);modo da poter ottenere quei valori getScollX/Ysolo se hai solo bisogno dei relativi coodinati.
Xander,

2
Questa dovrebbe essere una risposta accettata. getLocationOnScreen funziona così come getGlobalVisibleRect. Ma getGlobalVisibleRect fornisce un po 'più di informazioni e non è necessario lavorare con array grezzi. Vorrei quindi andare con getGlobalVisibleRect. L'utilizzo è semplice. Rect positionRect = new Rect (); view.getGlobablVisibleRect (positionRect); // x = positionRect.left // y = positionRect.top. evviva
JacksOnF1re

se una parte del bambino è al di fuori che non prenderà in considerazione in questo caso. come risolvere questo caso?
DKV

Bella risposta! Grazie mille!
Rohit Kumar,

8

Puoi usare `

view.getLocationOnScreen (int [] location)

; `per ottenere correttamente la posizione della vista.

Ma c'è un fermo se lo si utilizza prima di layout è stato gonfiato otterrete posizione sbagliata.

La soluzione a questo problema sta aggiungendo in ViewTreeObserverquesto modo: -

Dichiarare globalmente l'array per memorizzare la posizione xy della vista

 int[] img_coordinates = new int[2];

e quindi aggiungi ViewTreeObserveril layout del tuo genitore per ottenere il callback per l'inflazione del layout e solo allora recupera la posizione della vista, altrimenti otterrai coordinate xy errate

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

e poi usalo in questo modo

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

3

Mi sono scritto due metodi di utilità che sembrano funzionare nella maggior parte delle condizioni, gestendo scroll, traduzione e ridimensionamento, ma non rotazione. L'ho fatto dopo aver provato a usare offsetDescendantRectToMyCoords () nel framework, che aveva una precisione incoerente. Ha funzionato in alcuni casi, ma ha dato risultati sbagliati in altri.

"point" è un array float con due elementi (le coordinate x & y), "antenato" è un viewgroup da qualche parte sopra il "discendente" nella gerarchia dell'albero.

Innanzitutto un metodo che va dalle coordinate discendenti all'antenato:

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

Quindi l'inverso, dall'antenato al discendente:

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

Nel caso qualcuno stia ancora cercando di capirlo. Questo è come ottieni il centro X e Y del view.

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

1

Ho appena trovato la risposta qui

Dice: è possibile recuperare la posizione di una vista richiamando i metodi getLeft () e getTop (). Il primo restituisce la coordinata sinistra, o X, del rettangolo che rappresenta la vista. Quest'ultimo restituisce la coordinata superiore, o Y, del rettangolo che rappresenta la vista. Questi metodi restituiscono entrambi la posizione della vista rispetto al suo genitore. Ad esempio, quando getLeft () restituisce 20, significa che la vista si trova 20 pixel a destra del bordo sinistro del suo genitore diretto.

quindi usa:

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
Ciò fornisce la posizione relativa al genitore immediato della vista, non alla vista principale, che potrebbe essere il genitore del genitore, ecc ...
Rupert Rawnsley,

qual è la vista viene ridimensionata e ruotata?
DKV,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.