GetLocationOnScreen() vs getLocationInWindow()

В чем разница между экраном и представлением в контексте этих двух методов?

У меня есть кнопка, и я хочу получить координату x своего центра.

Я думаю, этого было бы достаточно:

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

но тогда какая разница, если бы я использовал

getLocationOnScreen() или getLocationInWindow()?

(добавив, конечно, половину ширины кнопки)

Ответ 1

Примечание. Этот ответ не был принятым ответом, когда он был написан, поэтому он сформулирован как опровержение другого ответа

Я не думаю, что принятый ответ правильный. Если я создаю новый проект и редактирую только MainActivity, добавив следующий фрагмент:

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

Я буду печатать на консоли 108 108. Это использует Nexus 7 с 4.3. У меня есть аналогичные результаты с использованием эмуляторов, работающих под управлением версий Android еще 2.2.

В нормальных окнах активности будет FILL_PARENTxFILL_PARENT как их WindowManager.LayoutParams, в результате чего они будут выкладываться на размер всего экрана. Окно выложено снизу (относительно z-порядка, а не y-координат), статусной панели и других украшений, поэтому я считаю, что более точная диаграмма будет:

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

Если вы перейдете через источник этих двух методов, вы увидите, что getLocationInWindow пересекает вашу иерархию представлений вида до RootViewImpl, суммирует координаты вида и вычитая смещения родительских прокруток. В случае, описанном выше, ViewRootImpl получает высоту строки состояния из WindowSession и передает ее через fitSystemWindows в ActionBarOverlayLayout, которая добавляет это значение к высоте панели действий. ActionBarOverlayLayout затем берет это суммарное значение и применяет его к своему представлению содержимого, которое является родительским элементом вашего макета, в качестве поля.

Таким образом, ваш контент располагается ниже строки состояния не в результате окна, начинающегося с более низкой координаты y, чем строки состояния, а вместо этого в результате применения поля к виду вашей активности.

Если вы заглянете в источник getLocationOnScreen, вы увидите, что он просто вызывает getLocationInWindow, а затем добавляет оконные левые и верхние координаты (которые также передаются в View by ViewRootImpl, который извлекает их из WindowSession). В нормальном случае эти значения будут равны нулю. Существуют ситуации, когда эти значения могут быть ненулевыми, например, диалоговое окно, расположенное посередине экрана.


Итак, подведем итог: нормальное окно активности заполняет весь экран, даже пространство под строкой состояния и украшениями. Эти два метода возвращают те же координаты x и y. Только в особых случаях, таких как диалоги, где Окно фактически смещено, эти два значения отличаются.

Ответ 2

getLocationOnScreen() получит местоположение на основе экрана телефона.

getLocationInWindow() получит местоположение на основе окна активности.

Для нормальной деятельности (не полноэкранная активность) отношение к экрану телефона и окну активности, как показано ниже:

| - экран телефона --------------------- |
| -------- строка состояния --------------------- |
|                                                       |
| ------------------------------------------- |
| -------- окно активности ------ ------- |
|                                                       |
|                                                       |
|                                                       |
|                                                       |
|                                                       |
|                                                       |
  | ------------------------------------------- |

Для координаты x значение обоих методов обычно одинаково.

Для координаты y значения имеют разницу для высоты строки состояния