views:

680

answers:

4

Hi,

I'm trying to get the absolute screen pixel coordinates of the top left corner of a view. However, all methods I can find such as getLeft() and getRight() don't work as they all seem to be relative to the parent of the view, thus giving me 0. What is the proper way to do this?

If it helps, this is for a 'put the picture back in order' game. I want the user to be able to draw a box to select multiple pieces. My assumption is that the easiest way to do that is to getRawX() and getRawY() from the MotionEvent and then compare those values against the top left corner of the layout holding the pieces. Knowing the size of the pieces, I can then determine how many pieces have been selected. I realise I can use getX() and getY() on the MotionEvent, but as that returns a relative position that makes determining which pieces were selected more difficult. (Not impossible, I know, but it seems unnecessarily complicated).

Thanks!

Edit: This is the code I used to try to get the size of the holding container, as per one of the questions. TableLayout is the table which holds all the puzzle pieces.

TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
Log.d(LOG_TAG, "Values " + tableLayout.getTop() + tableLayout.getLeft());

Edit 2: Here is the code I've tried, following more of the suggested answers.

public int[] tableLayoutCorners = new int[2];
(...)

TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
tableLayout.requestLayout();
Rect corners = new Rect();
tableLayout.getLocalVisibleRect(corners);
Log.d(LOG_TAG, "Top left " + corners.top + ", " + corners.left + ", " + corners.right
            + ", " + corners.bottom);

cells[4].getLocationOnScreen(tableLayoutCorners);
Log.d(LOG_TAG, "Values " + tableLayoutCorners[0] + ", " + tableLayoutCorners[1]);

This code was added after all the initialisation is done. The image has been divided up into a array of ImageViews (the cells[] array) contained within a TableLayout. Cells[0] is the top left ImageView, and I picked cells[4] as it's somewhere in the middle and most definitely should not have coordinates of (0,0).

The code shown above still gives me all 0s in the logs, which I really don't understand because the various puzzle pieces are correctly displayed. (I tried public int for tableLayoutCorners and default visibility, both giving the same result.)

I don't know if this is significant, but the ImageViews are originally not given a size. The size of the ImageViews is determined during the initilisation automatically by the View when I give it an image to display. Could this contribute to their values being 0, even though that logging code is after they have been given an image and have automatically resized themselves? To potentially counter that, I added the code tableLayout.requestLayout() as shown above, but that didn't help.

I'm stumped... Thanks again to anyone who can help.

A: 

Hmmm I'm a web dev guy and I deal with UI design using jQuery and Javascript on a regular basis.. but if I may give you an input...

Whatever holds the images - if you get the getLeft() and getRight() values of the holding container first, you could use that as a relative value to calculate off of, no? Just a thought.. maybe it's different on an Android platform.

jeffkee
Unfortunately that doesn't work - or at least, what I'm trying isn't working. I'm still getting 0 for both presumably because it doesn't consider the title bar at the top of the application to be part of the view, even though the bar does get considered when getting screen pixels from getRawX().
Steve H
+1  A: 

Use View.getLocationOnScreen() and/or getLocationInWindow().

Romain Guy
Now that's the kind of function I expected to find. Unfortunately, I must not be using it properly. I realise it was a known bug that getLocationOnScreen gives a null pointer exception in Android v1.5 (the platform I'm coding for), but testing in v2.1 didn't work any better. Both methods gave me 0s for everything. I included a code snippet above.
Steve H
You can only invoke it *AFTER* layout has happened. You are calling the method before the views are positioned on screen.
Romain Guy
Aha, you're right though it wasn't obvious that I was doing that. Thanks! For anyone curious for more details, I've added an answer which explains what I mean.
Steve H
+1  A: 

First you have to get the localVisible rectangle of the view

For eg:-

    Rect rectf = new Rect();
    <imageView>or<view>.getLocalVisibleRect(rectf);

Log.d("WIDTH        :",String.valueOf(rectf.width()));
Log.d("HEIGHT       :",String.valueOf(rectf.height()));
Log.d("left         :",String.valueOf(rectf.left));
Log.d("right        :",String.valueOf(rectf.right));
Log.d("top          :",String.valueOf(rectf.top));
Log.d("bottom       :",String.valueOf(rectf.bottom));`

Hope this will help

Naveen Murthy
That also should have worked... However it's giving me values of 0 as well. I included a code snippet above if that helps you figure out what I did wrong. Thanks again.
Steve H
See my other comments; I was accidentally calling this before the Views had finished laying themselves out. This works fine now thanks.
Steve H
A: 

Following Romain Guy's comment, here's how I fixed it. Hopefully it'll help anyone else who also had this problem.

I was indeed trying to get the positions of the views before they had been laid out on the screen but it wasn't at all obvious that was happening. Those lines had been placed after the initilisation code ran, so I assumed everything was ready. However, this code was still in onCreate(); by experimenting with Thread.sleep() I discovered that the layout is not actually finalised until after onCreate() all the way to onResume() had finished executing. So indeed, the code was trying to run before the layout had finished being positioned on the screen. By adding the code to an OnClickListener (or some other Listener) the correct values were obtained because it could only be fired after the layout had finished.

Steve H