我不认为这个答案是正确的。如果我创建一个新项目,并通过添加以下代码段仅编辑 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);
}
我会看到打印到控制台。这是使用运行4.3的Nexus 7。我使用运行Android版本的模拟器获得类似的结果,最早可追溯到2.2。108 108
正常活动窗口将具有FILL_PARENTxFILL_PARENT作为其 WindowManager.LayoutParams,这导致它们布局到整个屏幕的大小。窗口位于状态栏和其他装饰下方(关于z顺序,而不是y坐标),因此我相信更准确的图表是:
|--phone screen-----activity window---|
|--------status bar-------------------|
| |
| |
|-------------------------------------|
如果单步执行这两种方法的源,您将看到视图的视图层次结构向上遍历到 RootViewImpl,对视图坐标求和并减去父滚动偏移量。在我上面描述的情况下,ViewRootImpl从WindowSession获取状态栏高度,并通过fitSystemWindows将其传递到ActionBarOverlayLayout,后者将此值添加到操作栏高度。然后,ActionBarOverlayLayout 获取此求和值,并将其作为边距应用于其内容视图(即布局的父级)。getLocationInWindow
因此,您的内容布局低于状态栏,不是由于窗口从比状态栏更低的 y 坐标开始,而是由于将边距应用于活动的内容视图。
如果你窥视源代码,你会看到它只是调用,然后添加窗口的左侧和顶部坐标(这些坐标也由ViewRootImpl传递给View,后者从WindowSession中获取它们)。在正常情况下,这些值都将为零。在某些情况下,这些值可能不为零,例如,放置在屏幕中间的对话窗口。getLocationOnScreen
getLocationInWindow
因此,总而言之:正常活动的窗口会填满整个屏幕,甚至是状态栏和装饰品下方的空间。所讨论的两种方法将返回相同的 x 和 y 坐标。只有在特殊情况下,例如窗口实际偏移的对话框,这两个值才会有所不同。