Ответ 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. Только в особых случаях, таких как диалоги, где Окно фактически смещено, эти два значения отличаются.