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