71 votes

getLocationOnScreen() vs getLocationInWindow()

Quelle est la différence entre screen et view dans le contexte de ces deux méthodes ?

J'ai un bouton et je veux obtenir la coordonnée x de son centre.

Je suppose que ça suffira :

public int getButtonXPosition() {
    return (button.getLeft()+button.getRight())/2;
}

mais alors, quelle différence cela ferait-il si j'avais utilisé

getLocationOnScreen() ou getLocationInWindow() ?

(en y ajoutant la moitié de la largeur du bouton, bien sûr)

1 votes

Avec Android N et son support multi-fenêtres ( developer.Android.com/preview/features/multi-window.html ), vous devriez probablement préférer getLocationInWindow() à getLocationOnScreen(), car cette dernière peut entraîner un comportement inattendu.

120voto

groucho Points 588

Je ne pense pas que cette réponse est correcte. Si je crée un nouveau projet, et que je modifie uniquement l'activité principale en ajoutant l'extrait suivant :

public boolean dispatchTouchEvent(MotionEvent ev) {
    View contentsView = findViewById(android.R.id.content);

    int test1[] = new int[2];
    contentsView.getLocationInWindow(test1);

    int test2[] = new int[2];
    contentsView.getLocationOnScreen(test2);

    System.out.println(test1[1] + " " + test2[1]);

    return super.dispatchTouchEvent(ev);
}

Je verrai s'afficher dans la console 108 108 . J'utilise une Nexus 7 sous la version 4.3. J'ai obtenu des résultats similaires avec des émulateurs utilisant des versions d'Android aussi anciennes que la 2.2.

Les fenêtres d'activité normale auront pour paramètres de disposition WindowManager.LayoutParams FILL_PARENTxFILL_PARENT, ce qui leur permet de s'étendre à la taille de l'écran entier. La fenêtre est disposée sous (en ce qui concerne l'ordre z, pas les coordonnées y) la barre d'état et d'autres décorations, donc je pense qu'un tableau plus précis serait :

|--phone screen-----activity window---| 
|--------status bar-------------------| 
|                                     | 
|                                     | 
|-------------------------------------| 

Si vous parcourez la source de ces deux méthodes, vous verrez que getLocationInWindow parcourt la hiérarchie des vues de votre vue jusqu'au RootViewImpl, en additionnant les coordonnées de la vue et en soustrayant les décalages de défilement des parents. en soustrayant les décalages de défilement du parent. Dans le cas que j'ai décrit ci-dessus, le ViewRootImpl obtient la hauteur de la barre d'état de la WindowSession et la transmet, via fitSystemWindows, à l'ActionBarOverlayLayout, qui ajoute cette valeur à la hauteur de la barre d'action. L'ActionBarOverlayLayout prend ensuite cette valeur additionnée et l'applique à sa vue de contenu, qui est le parent de votre mise en page, comme une marge.

Ainsi, votre contenu est disposé plus bas que la barre d'état, non pas parce que la fenêtre commence à une coordonnée y inférieure à celle de la barre d'état, mais parce qu'une marge est appliquée à la vue du contenu de votre activité.

Si vous regardez dans le getLocationOnScreen source que vous verrez qu'elle appelle simplement getLocationInWindow et ajoute ensuite les coordonnées de gauche et de haut de la fenêtre (qui sont également transmises à la vue par ViewRootImpl, qui les récupère dans WindowSession). Dans le cas normal, ces valeurs seront toutes deux égales à zéro. Dans certaines situations, ces valeurs peuvent être différentes de zéro, par exemple une fenêtre de dialogue placée au milieu de l'écran.


Donc, pour résumer : La fenêtre d'une activité normale remplit tout l'écran, même l'espace sous la barre d'état et les décorations. Les deux méthodes en question renverront les mêmes coordonnées x et y. Ce n'est que dans des cas particuliers, comme les boîtes de dialogue où la fenêtre est effectivement décalée, que ces deux valeurs seront différentes.

0 votes

Pourquoi ma fenêtre d'activité rétrécit-elle si j'ajoute une barre de navigation à l'écran dans mon téléphone ? C'est aussi un décor comme la barre d'état.

35voto

Ivan Points 267

getLocationOnScreen() obtiendra l'emplacement basé sur le écran du téléphone .
getLocationInWindow() obtiendra l'emplacement basé sur le fenêtre d'activité .

Pour le activité normale (pas d'activité en plein écran), la relation entre l'écran du téléphone et la fenêtre d'activité est la suivante :

|--------phone screen--------|
|---------status bar---------|
|                            |
|----------------------------|
|------activity window-------|
|                            |
|                            |
|                            |
|                            |
|                            |
|                            |
|----------------------------|

Pour le x coordonnée, la valeur des deux méthodes est généralement la même.
Pour le y coordonnée, les valeurs ont une différence pour la hauteur de la barre d'état.

13 votes

Cette réponse est incompatible avec ce que j'observe lorsque je crée un projet vide et que j'appelle ces deux méthodes. J'ai expliqué plus en détail dans une réponse ci-dessous.

12voto

Suragch Points 197

La réponse actuellement acceptée est un peu verbeuse. En voici une plus courte.

getLocationOnScreen() et getLocationInWindow() renvoient normalement les mêmes valeurs. Cela est dû au fait que la fenêtre a normalement la même taille que l'écran. Cependant, il arrive que la fenêtre soit plus petite que l'écran. Par exemple, dans un Dialog ou un clavier système personnalisé.

Ainsi, si vous savez que les coordonnées que vous voulez sont toujours relatives à l'écran (comme dans une activité normale), alors vous pouvez utiliser getLocationOnScreen() . Cependant, si votre vue se trouve dans une fenêtre qui pourrait être plus petite que l'écran (comme dans une boîte de dialogue ou un clavier personnalisé), alors utilisez la fonction getLocationInWindow() .

Related

5voto

Gibolt Points 4072

Pour getLocationOnScreen() , x et y renverra le coin supérieur gauche de la vue.

Utilisation de getLocationInWindow() sera relative à son conteneur, et non à l'ensemble de l'écran. Ce sera différent de getLocationOnScreen() si la disposition de votre racine est plus petite que l'écran (comme dans une boîte de dialogue). Dans la plupart des cas, ils seront identiques.

NOTE : Si la valeur est toujours 0, il est probable que vous modifiez la vue immédiatement avant de demander l'emplacement. Vous pouvez utiliser view.post pour s'assurer que les valeurs sont disponibles

Solution Java

int[] point = new int[2];
view.getLocationOnScreen(point); // or getLocationInWindow(point)
int x = point[0];
int y = point[1];

Pour vous assurer que la vue a eu l'occasion de se mettre à jour, exécutez votre demande de localisation après que la nouvelle disposition de la vue a été calculée en utilisant view.post :

view.post(() -> {
    // Values should no longer be 0
    int[] point = new int[2];
    view.getLocationOnScreen(point); // or getLocationInWindow(point)
    int x = point[0];
    int y = point[1];
});

~~

Solution Kotlin

val point = IntArray(2)
view.getLocationOnScreen(point) // or getLocationInWindow(point)
val (x, y) = point

Pour vous assurer que la vue a eu l'occasion de se mettre à jour, exécutez votre demande de localisation après que la nouvelle disposition de la vue a été calculée en utilisant view.post :

view.post {
    // Values should no longer be 0
    val point = IntArray(2)
    view.getLocationOnScreen(point) // or getLocationInWindow(point)
    val (x, y) = point
}

Je recommande de créer une fonction d'extension pour gérer cela :

// To use, call:
val (x, y) = view.screenLocation

val View.screenLocation get(): IntArray {
    val point = IntArray(2)
    getLocationOnScreen(point)
    return point
}

Et si vous avez besoin de fiabilité, ajoutez aussi :

// To use, call:
view.screenLocationSafe { x, y -> Log.d("", "Use $x and $y here") }

fun View.screenLocationSafe(callback: (Int, Int) -> Unit) {
    post {
        val (x, y) = screenLocation
        callback(x, y)
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X