有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java getLocationOnScreen()与getLocationInWindow()的比较

在这两种方法的上下文中,screen和view之间有什么区别

我有一个按钮,我想得到它中心的x坐标

我想这就足够了:

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

但是,如果我使用

getLocationOnScreen()还是getLocationInWindow()

(当然,还要加上按钮宽度的一半)


共 (4) 个答案

  1. # 1 楼答案

    getLocationOnScreen()将根据手机屏幕获取位置
    getLocationInWindow()将根据活动窗口获取位置

    对于正常活动(非全屏活动),与手机屏幕和活动窗口的关系如下所示:

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

    对于x坐标,两种方法的值通常相同
    对于y坐标,这些值与状态栏的高度不同

  2. # 2 楼答案

    我认为this answer是不对的。如果我创建了一个新项目,并通过添加以下代码片段仅编辑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的Nexus7。我使用运行早在2.2版本的android的模拟器得到了类似的结果

    正常活动窗口将使用FILL_PARENTxFILL_Parents作为窗口管理器。LayoutParams,这会导致它们按照整个屏幕的大小进行布局。窗口位于状态栏和其他装饰的下方(相对于z坐标,而不是y坐标),因此我认为更准确的图表应该是:

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

    如果仔细查看这两个方法的源代码,您将看到getLocationInWindow沿着视图的视图层次向上遍历到RootViewImpl,将视图坐标和 减去父滚动偏移。在我上面描述的例子中,ViewRootImpl从WindowsSession获取状态栏高度,并通过fitSystemWindows将其传递到ActionBarOverlayLayout,从而将该值添加到actionbar高度。ActionBarOverlayLayout然后将该求和值作为边距应用于其内容视图,该视图是布局的父视图

    因此,内容的布局低于状态栏,不是因为窗口的y坐标低于状态栏,而是因为活动的内容视图应用了边距

    如果你查看getLocationOnScreen源代码,你会发现它只会调用getLocationInWindow,然后添加窗口的左坐标和上坐标(这些坐标也由ViewRootImpl传递给视图,后者从WindowsSession获取它们)。在正常情况下,这些值都将为零。有些情况下,这些值可能是非零的,例如放置在屏幕中间的对话框窗口。


    因此,总结一下:一个正常活动的窗口占据了整个屏幕,甚至是状态栏和装饰下的空间。这两种方法将返回相同的x和y坐标。只有在特殊情况下,例如窗口实际偏移的对话框,这两个值才会不同

  3. # 3 楼答案

    目前公认的答案有点罗嗦。这是一个较短的

    getLocationOnScreen()getLocationInWindow()通常返回相同的值。这是因为窗口通常与屏幕大小相同。然而,有时窗口比屏幕小。例如,在Dialog或自定义系统键盘中

    因此,如果你知道你想要的坐标总是相对于屏幕的(就像在正常活动中),那么你可以使用getLocationOnScreen()。但是,如果视图所在的窗口可能比屏幕小(如对话框或自定义键盘),则使用getLocationInWindow()

    相关的

  4. # 4 楼答案

    对于^{}xy将返回视图的左上角

    使用^{}将是相对于其容器的,而不是整个屏幕。如果根布局小于屏幕(如在对话框中),则这将不同于getLocationOnScreen()。在大多数情况下,它们是相同的

    NOTE: If value is always 0, you are likely changing the view immediately before requesting location. You can use view.post to ensure the values are available

    Java解决方案

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

    要确保视图有机会更新,请在使用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];
    });
    

    ~~

    科特林溶液

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

    要确保视图有机会更新,请在使用view.post计算视图的新布局后运行位置请求:

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

    我建议创建一个扩展函数来处理这个问题:

    // To use, call:
    val (x, y) = view.screenLocation
    
    val View.screenLocation get(): IntArray {
        val point = IntArray(2)
        getLocationOnScreen(point)
        return point
    }
    

    如果您需要可靠性,还可以添加:

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