238

The position of a UIView can obviously be determined by view.center or view.frame etc. but this only returns the position of the UIView in relation to it's immediate superview.

I need to determine the position of the UIView in the entire 320x480 co-ordinate system. For example, if the UIView is in a UITableViewCell it's position within the window could change dramatically irregardless of the superview.

Any ideas if and how this is possible?

starball
  • 20,030
  • 7
  • 43
  • 238
adam
  • 22,404
  • 20
  • 87
  • 119

8 Answers8

365

That's an easy one:

[aView convertPoint:localPosition toView:nil];

... converts a point in local coordinate space to window coordinates. You can use this method to calculate a view's origin in window space like this:

[aView.superview convertPoint:aView.frame.origin toView:nil];

2014 Edit: Looking at the popularity of Matt__C's comment it seems reasonable to point out that the coordinates...

  1. don't change when rotating the device.
  2. always have their origin in the top left corner of the unrotated screen.
  3. are window coordinates: The coordinate system ist defined by the bounds of the window. The screen's and device coordinate systems are different and should not be mixed up with window coordinates.
Nikolai Ruhe
  • 81,520
  • 17
  • 180
  • 200
  • awesome :) I thought it should be simple, but I had the feeling apple wouldn't give it so easy... well they did. thanks – Lior Frenkel May 15 '11 at 14:19
  • I added a different question - it worked for me in simulator but not on the real device :( – Lior Frenkel May 16 '11 at 06:14
  • 44
    Be aware that specifying nil in the toView parameter gives you device co-ordinates, which won't be what you want if you are not in portrait orientation. See [convertpointtoview-in-landscape-mode-giving-wrong-values](http://stackoverflow.com/questions/6452716/convertpointtoview-in-landscape-mode-giving-wrong-values) – Matt__C Jan 19 '12 at 18:43
  • @Matt__C: Specifying nil calculates **window coordinates**, not device coordinates. If you want device coordinates you have to further convert using UIWindow's conversion methods. – Nikolai Ruhe Jan 20 '12 at 12:25
  • 2
    This method kept returning `aView.frame.origin` for me. It took me a whlie to realize my view's superview did not have a superview itself. – Dan Abramov Dec 10 '12 at 19:57
  • 4
    If your superView did not have a superView your view should not be seen at all – user4951 Mar 19 '13 at 03:41
  • @JimThio To be super-precise: If the view's superview was a window it **would** be visible. On iOS `UIWindow` derives fron `UIView`. – Nikolai Ruhe Nov 22 '13 at 13:12
  • This isn't working at all for me. Converting (0,0) on a view is giving me negative coordinates! How is that even possible? – devios1 Aug 22 '14 at 00:36
  • @chaiguy If the view's origin is to the left or above the screen's top left corner its window coordinates will, of course, be negative. – Nikolai Ruhe Aug 22 '14 at 09:15
  • I think the problem was that the tableView must have been in a scrollView or something. I wasn't expecting that. Got it figured out. – devios1 Aug 22 '14 at 17:15
  • 17
    Adapting @Matt__C linked solution to your case, it would become: `[view.superview convertPoint:view.frame.origin toView:[UIApplication sharedApplication].keyWindow.rootViewController.view]` – Ghigo Oct 31 '14 at 14:31
  • @Ghigo this perfectly works to get the position - how would I use this information however to set a view relative to the screen without using autolayout? – trdavidson Jan 16 '15 at 00:05
  • I've been trying to do this with a UIToolbar. I need to determine the horizontal margins the system uses for bar button items so that I can adjust my layout (these margins have changed between iOS versions and are different between iPhone and iPad). For the life of me I can't figure it out...no matter what combination of views I supply as arguments and receiver to the method, origin is always (0, 7). Any tips? – Reid Aug 17 '16 at 22:46
77

Swift 5+:

let globalPoint = aView.superview?.convert(aView.frame.origin, to: nil)
Yuchen
  • 30,852
  • 26
  • 164
  • 234
46

Swift 3, with extension:

extension UIView{
    var globalPoint :CGPoint? {
        return self.superview?.convert(self.frame.origin, to: nil)
    }

    var globalFrame :CGRect? {
        return self.superview?.convert(self.frame, to: nil)
    }
}
Mohsenasm
  • 2,916
  • 1
  • 18
  • 22
36

In Swift:

let globalPoint = aView.superview?.convertPoint(aView.frame.origin, toView: nil)
Shlomi Schwartz
  • 8,693
  • 29
  • 109
  • 186
28

Here is a combination of the answer by @Mohsenasm and a comment from @Ghigo adopted to Swift

extension UIView {
    var globalFrame: CGRect? {
        let rootView = UIApplication.shared.keyWindow?.rootViewController?.view
        return self.superview?.convert(self.frame, to: rootView)
    }
}
Zaporozhchenko Oleksandr
  • 4,660
  • 3
  • 26
  • 48
Allan Spreys
  • 5,287
  • 5
  • 39
  • 44
4

For me this code worked best:

private func getCoordinate(_ view: UIView) -> CGPoint {
    var x = view.frame.origin.x
    var y = view.frame.origin.y
    var oldView = view

    while let superView = oldView.superview {
        x += superView.frame.origin.x
        y += superView.frame.origin.y
        if superView.next is UIViewController {
            break //superView is the rootView of a UIViewController
        }
        oldView = superView
    }

    return CGPoint(x: x, y: y)
}
Hugo Jordao
  • 786
  • 8
  • 9
3

Works well for me :)

extension UIView {
    var globalFrame: CGRect {
        return convert(bounds, to: window)
    }
}
AKIL KUMAR
  • 287
  • 3
  • 8
1

this worked for me

view.layoutIfNeeded() // this might be necessary depending on when you need to get the frame

guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return }

let frame = yourView.convert(yourView.bounds, to: keyWindow)

print("frame: ", frame)
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256