Obtenir les coordonnées de View par rapport à la disposition racine

142

Puis-je obtenir la position x et y d'une vue par rapport à la disposition racine de mon activité dans Android?

fhucho
la source

Réponses:

138

C'est une solution, cependant, puisque les API changent avec le temps et qu'il peut y avoir d'autres façons de le faire, assurez-vous de vérifier les autres réponses. L'un prétend être plus rapide et un autre prétend être plus facile.

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

Faites-moi savoir si cela fonctionne.

Il devrait simplement ajouter récursivement les positions supérieure et gauche de chaque conteneur parent. Vous pouvez également l'implémenter avec un Pointsi vous le souhaitez.

Ramblinjan
la source
getRelativeLeft () il faut ajouter un cast, mais quand j'ajoute (View) ou (button) ((Object) myView.getParent ()). getRelativeTop (), ce n'est pas non plus correct
pengwang
J'ai fait quelque chose de très similaire mais j'ai vérifié la vue racine par getId == R.id.myRootView.
fhucho
1
Log.i ("RelativeLeft", "" + getRelativeLeft (findViewById (R.id.tv))); Log.i ("RelativeTop", "" + getRelativeTop (findViewById (R.id.tv))); j'obtiens tout est 0; textView dans la mise en page est le suivant <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
Une approche souriante comme celle-ci (la calculer manuellement) a fonctionné pour moi, j'ai donc accepté cette réponse.
fhucho
3
l'api android fournit déjà la coordonnée relative à la racine. regardez ici stackoverflow.com/a/36740277/2008214
carlo.marinangeli
155

L'API Android fournit déjà une méthode pour y parvenir. Essaye ça:

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;

Voici le doc

carlo.marinangeli
la source
16
Cela devrait être la réponse acceptée. Aucune possibilité de débordement de pile, et aucune possibilité d'erreurs mathématiques. Merci!
GLee
Je suis d'accord, cela devrait être la réponse acceptée - il ne reste que 92 votes à la hausse.
étourdi
Je voulais trouver les coordonnées d'une vue dans la barre d'outils. C'est la seule méthode qui fonctionne de manière cohérente pour prendre en compte Android: correspond à Windows et à diverses versions d'API de 19 à 27. Alors merci! C'est la bonne réponse.
David Ferrand
A travaillé parfaitement
Rawa
Cela a très bien fonctionné, je veux juste mentionner qu'il parentViewGrouppeut s'agir de n'importe quel parent dans la hiérarchie des vues, donc cela fonctionne parfaitement pour ScrollView également.
Sira Lam
93

Veuillez utiliser view.getLocationOnScreen(int[] location);(voir Javadocs ). La réponse est dans le tableau d'entiers (x = location[0]et y = location[1]).

BinaireTofu
la source
13
Cela renvoie la position rlative à l'écran et non à la disposition racine de l'activité.
fhucho
10
Il existe également View.getLocationInWindow (int []) qui renvoie la position de la vue par rapport à la fenêtre.
Rubicon
Pouvez-vous me dire exactement comment cette méthode fonctionne. Il retourne un vide comment faire pour obtenir la sortie ou les valeurs x, y d'une vue à l'écran
user1106888
6
Pour obtenir la position relative à la disposition racine, appelez simplement getLocationInWindow pour la disposition racine et l'élément, et utilisez la puissance de la soustraction. C'est beaucoup plus simple et probablement plus rapide que la réponse acceptée.
Blake Miller
1
il s'agit simplement de l'emplacement lié à l'écran. pas la racine. lisez ici pour les informations relatives à la racine: 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];

J'obtiens d'abord la disposition racine, puis je calcule la différence de coordonnées avec la vue.
Vous pouvez également utiliser le à la getLocationOnScreen()place de getLocationInWindow().

Kerrmiter
la source
3
quelle est la vue est mise à l'échelle et pivotée?
DKV
C'est la seule réponse qui fonctionne pour moi. Cela devrait être accepté réponse
neoexpert
36

Pas besoin de le calculer manuellement.

Utilisez simplement getGlobalVisibleRect comme ceci:

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

Notez également que pour les coordonnées du centre, plutôt que quelque chose comme:

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

Vous pouvez simplement faire:

float cx = myViewRect.exactCenterX();
float cy = myViewRect.exactCenterY();
Grand
la source
En regardant la source Android, tout getGlobalVisibleRectest fait globalOffset.set(-mScrollX, -mScrollY);pour que vous puissiez simplement obtenir ces valeurs avec getScollX/Ysi vous n'avez besoin que des coodinates relatifs.
Xander
2
Cela devrait être une réponse acceptée. getLocationOnScreen fonctionne aussi bien que getGlobalVisibleRect. Mais getGlobalVisibleRect fournit un peu plus d'informations et il n'est pas nécessaire de travailler avec des tableaux bruts. J'irais donc avec getGlobalVisibleRect. L'utilisation est simple. Rect positionRect = nouveau Rect (); view.getGlobablVisibleRect (positionRect); // x = positionRect.left // y = positionRect.top. cheers
JacksOnF1re
si une partie de l'enfant est à l'extérieur qui ne sera pas prise en considération dans ce cas. comment résoudre un tel cas?
DKV
Très bonne réponse! Merci beaucoup!
Rohit Kumar
8

Vous pouvez utiliser `

view.getLocationOnScreen (int [] emplacement)

; `pour obtenir correctement l'emplacement de votre vue.

Mais il y a une prise si vous utilisez avant la mise en page vous a été gonflé obtiendrez une mauvaise position.

La solution à ce problème est d'ajouter ViewTreeObservercomme ceci: -

Déclarez globalement le tableau pour stocker la position xy de votre vue

 int[] img_coordinates = new int[2];

puis ajoutez ViewTreeObservervotre mise en page parent pour obtenir un rappel pour l'inflation de la mise en page, puis récupérez la position de la vue, sinon vous obtiendrez de mauvaises coordonnées 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);
                        }
                    }
            );

puis utilisez-le comme ça

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

Je me suis écrit deux méthodes utilitaires qui semblent fonctionner dans la plupart des conditions, la gestion du défilement, de la traduction et de la mise à l'échelle, mais pas de la rotation. Je l'ai fait après avoir essayé d'utiliser offsetDescendantRectToMyCoords () dans le cadre, qui avait une précision incohérente. Cela a fonctionné dans certains cas, mais a donné de mauvais résultats dans d'autres.

"point" est un tableau flottant avec deux éléments (les coordonnées x & y), "ancestor" est un groupe de vues quelque part au-dessus du "descendant" dans la hiérarchie de l'arborescence.

D'abord une méthode qui va des coordonnées descendantes à l'ancêtre:

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

Ensuite l'inverse, de l'ancêtre au descendant:

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;
}
Alexandre Hugestrand
la source
2

Incase quelqu'un essaie toujours de comprendre cela. C'est ainsi que vous obtenez le centre X et Y du 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
la source
1

Je viens de trouver la réponse ici

Il dit: Il est possible de récupérer l'emplacement d'une vue en appelant les méthodes getLeft () et getTop (). Le premier renvoie la coordonnée gauche, ou X, du rectangle représentant la vue. Ce dernier retourne la coordonnée supérieure, ou Y, du rectangle représentant la vue. Ces méthodes renvoient toutes deux l'emplacement de la vue par rapport à son parent. Par exemple, lorsque getLeft () renvoie 20, cela signifie que la vue est située à 20 pixels à droite du bord gauche de son parent direct.

alors utilisez:

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
la source
1
Cela donne l'emplacement par rapport au parent immédiat de la vue, pas à la vue racine, qui pourrait être le parent du parent etc ...
Rupert Rawnsley
quelle est la vue est mise à l'échelle et pivotée?
DKV