Android’s view system is designed to handle layout and view positions automatically. A developer never sets the absolute position of a view in a layout. Instead, we rely on layouts to define constraints. However, sometimes, especially when handling view animations, we need to determine the position of a view. Android provides a number of ways to measure the position of views and viewgroups, but the documentation is sparse at best. Furthermore, I couldn’t find a good summary online, so I’m providing the following learnings.

TL;DR

There are three main ways of measuring the X,Y coordinates of a View or ViewGroup, and two that aren’t that useful.

Android Coordinate System

First, let’s start with the basics. In Android, the top left of the screen is (0,0). Positive x is to the right, and positive y is down. The status bar is overlaid on the window, so (0,0) is the top left of the status bar. Normally, a developer specifies a layout using density independent pixels (dp) to account for different screen densities. For instance, on my LG Nexus 5 (xxhdpi), dp values are multiplied by three to get the pixel value. All of the following methods return their values in plain old pixels.

Methods

getLocationOnScreen()

getLocationOnScreen() is simple, it returns the absolute position of the view on the screen, disregarding everything else. It returns integer values in plain old pixels. I find the api to be a little bit awkward because you have to pass an array to the method, which then gets populated with the values. It feels like a little bit of C style memory management leaking into our object-oriented, high level world.

int location[] = new int[2];
view.getLocationOnScreen(location);

getLocationInWindow()

getLocationInWindow() behaves similarly to getLocationOnScreen() in its api and return values, and in most situations it will return the same result. However, as the name suggests, this method will return a different value if the current window differs from the full screen. “Window” refers to the activity window, which is drawn behind the status bar, so the status bar is ignored. There seems to be some misinformation floating around the internet that getLocationInWindow() will subtract the height of the status bar, among other things, which is not true. I’ve verified this behavior down to API level 11.

int location[] = new int[2];
view.getLocationInWindow(location);

One example of when the window size can differ from the total screen size is a dialog that is not full screen. In this case, the window is the dialog window, and the margins around the dialog will be subtracted from the absolute values. In other words, (0,0) is the top left of the dialog window. However, in practice, there seems to be some margin added to the dialog, so a view that uses match_parent will NOT be positioned at (0,0) in a dialog, even if the same view would be positioned at (0,0) in an activity. In the example below, I’ve put the same ViewGroup inside of an activity, and then inside of a dialog box in that activity.

Left: Both onScreen and inWindow return the same values in an activity layout
Right: onScreen and inWindow return different values inside of a dialog window.

getX/Y()

getX() and getY() return the pixel coordinates as floats relative to the parent ViewGroup. For instance, if your view is inside a LinearLayout which is inside a RelativeLayout, these methods will return the coordinates relative to the LinearLayout. I find these methods to be easy to use, but dangerous because it can be easy to change the layout to nest or unnest the view, and thus change the way the view is being measured.

float x = view.getX();
float y = view.getY();

getGlobalVisibleRect()

getGlobalVisibleRect() is quite misleading, it actually pertains to clipping, not visibility. You pass it a Rect, which gets populated with a bounding box or not, and returns true or false based on whether the Rect got populated. The Rect is populated with the bounding box of the view that is not clipped by its parents, NOT what is actually visible on screen. Thus, if the view is completely covered by another view in the viewgroup, or even has visibility == INVISIBLE, the Rect will be populated and the method will return true. But, if the view has visibility == GONE or the view is completely clipped, this method returns false. You can view the source and the javadoc here, although they also take some deciphering.

Rect rect = new Rect();
view.getGlobalVisibleRect(rect);

getLocalVisibleRect()

getLocalVisibleRect() simply calls getGlobalVisibleRect(), with an offset applied. “Local” means in this view’s own coordinates, so the top left of the resulting Rect will always be (0,0), if the whole view is visible.

Rect rect = new Rect();
view.getLocalVisibleRect(rect);

Example

To demonstrate all of these methods, I have a quick and dirty Android app here. The three get coordinates methods are shown on master, and the two rect methods are on a branch. Enjoy!


Greg Lee

Greg Lee

Greg Lee was a Backend Engineer at Scoop, focusing on the engineering architecture and infrastructure serving Scoop carpoolers everywhere. In his spare time, Greg volunteers as a mobile developer and product manager for American Whitewater, a national nonprofit organization focused on the conservation, restoration, and safe enjoyment of America's whitewater resources.

Leave a Reply

Your email address will not be published. Required fields are marked *