Incorrect Coordinates from Getlocationonscreen/Getlocationinwindow

Incorrect Coordinates From getLocationOnScreen/getLocationInWindow

I ended up solving this issue by determining the height of the status/notification bar like so:

View globalView = ...; // the main view of my activity/application

DisplayMetrics dm = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(dm);
int topOffset = dm.heightPixels - globalView.getMeasuredHeight();

View tempView = ...; // the view you'd like to locate
int[] loc = new int[2];
tempView.getLocationOnScreen(loc);

final int y = loc[1] - topOffset;

Why are getLocationOnScreen() and getLocationInWindow() returning same values?

I was confused by this as well, so I did a bit of investigation that I summarize
here.

Basically, the window lays out beneath the status bar (beneath in regards to z-order not y-coordinates), and fills the entire screen, in most cases. So, in a normal activity you should expect these methods to return the same values. Only in unique cases, such as dialogs where the Window is actually offset, will you see these methods returning different values.

getLocationOnScreen() vs getLocationInWindow()

I don't think this answer is correct. If I create a new project, and edit only the MainActivity by adding the following snippet:

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

I will see printed to the console 108 108. This is using a Nexus 7 running 4.3. I have similar results using emulators running android versions as far back as 2.2.

Normal activity windows will have FILL_PARENTxFILL_PARENT as their WindowManager.LayoutParams, which results in them laying out to the size of the entire screen. The Window is laid out underneath (in regards to z-order, not y-coordinates) the statusbar and other decorations, so I believe a more accurate chart would be:

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

If you step through the source of these two methods, you will see that getLocationInWindow traverses up your view's view hierarchy up to the RootViewImpl, summing view coordinates and
subtracting parent scroll offsets. In the case I described above the ViewRootImpl is getting the status bar height from the WindowSession, and passing it down through fitSystemWindows to the ActionBarOverlayLayout, which adds this value to the actionbar height. ActionBarOverlayLayout then takes this summed value and applies it to its content view, which is the parent of your layout, as a margin.

So, your content is laid out lower than the status bar not as a result of the window starting at a lower y coordinate than the status bar, but instead as a result of a margin being applied to your activity's content view.

If you peer into the getLocationOnScreen source you'll see it merely calls getLocationInWindow and then adds the Window's left and top coords (which are also passed to the View by ViewRootImpl, which fetches them from the WindowSession). In the normal case, these values will both be zero. There are some situations where these values may be non-zero, for example a dialog window that is placed in the middle of the screen.


So, to summarize: A normal activity's window fills the entire screen, even the space under the status bar and decorations. The two methods in question will return the same x and y coordinates. Only in special cases such as dialogs where the Window is actually offset will these two values differ.

View.getLocationOnScreen does not work properly

Ok, I just understood the function wrong - maybe because I'm coming from the Microsoft .NET C# world where you can easily transform coordinates from control to screen and vice versa. Anyway, the view.getLocationOnScreen is just returning the transformed upper-left corner of the view. So you have to use it as an offset.

public static void getLocationOnScreen(View view, final Rect src, Rect dst) {
if (view == null || src == null)
return;

if (dst == null)
dst = new Rect();

int[] location = new int[2];
view.getLocationOnScreen(location);
int offsetX = location[0];
int offsetY = location[1];

dst.set(src.left + offsetX, src.top + offsetY, src.right + offsetX,
src.bottom + offsetY);
}

How to get exact position in pixels of my TextView?

I have a smartphone of 2560 x 1440 px... My TextView is pretty much in the middle of the screen, so supposedly at (1280,770).

Not correct, unless you talk about the center of the TextView. Any view is rendered on screen within its rectangle, so its coordinates are considered to be of [left, top, right, bottom].

The GetLocationInWindow() method returns (left, top) coordinates of a view. So (x = 69, y = 1111) looks to be meaningful for the left top corner of your TextView located in the middle of screen.

Important note: GetLocationInWindow() returns the coordinates w.r.t the root view, not actual window. You should take the status bar height into consideration. And here is how you can calculate Height of status bar in Android.



Related Topics



Leave a reply



Submit