Get position of UIView in respect to its superview's superview

I have a UIView, in which I have arranged UIButtons. I want to find the positions of those UIButtons.

I am aware that buttons.frame will give me the positions, but it will give me positions only with respect to its immediate superview.

Is there is any way we can find the positions of those buttons, withe respect to UIButtons superview's superview?

For instance, suppose there is UIView named "firstView".

Then, I have another UIView, "secondView". This "SecondView" is a subview of "firstView".

Then I have UIButton as a subview on the "secondView".

->UIViewController.view
--->FirstView A
------->SecondView B
------------>Button

Now, is there any way we can find the position of that UIButton, with respect to "firstView"?


You can use this:

Objective-C

CGRect frame = [firstView convertRect:buttons.frame fromView:secondView];

Swift

let frame = firstView.convert(buttons.frame, from:secondView)

Documentation reference:

https://developer.apple.com/documentation/uikit/uiview/1622498-convert


Although not specific to the button in the hierarchy as asked I found this easier to visualize and understand:

From here: original source

enter image description here

ObjC:

CGPoint point = [subview1 convertPoint:subview2.frame.origin toView:viewController.view];

Swift:

let point = subview1.convert(subview2.frame.origin, to: viewControll.view)

Updated for Swift 3

    if let frame = yourViewName.superview?.convert(yourViewName.frame, to: nil) {

        print(frame)
    }

enter image description here


UIView extension for converting subview's frame (inspired by @Rexb answer).

extension UIView {

    // there can be other views between `subview` and `self`
    func getConvertedFrame(fromSubview subview: UIView) -> CGRect? {
        // check if `subview` is a subview of self
        guard subview.isDescendant(of: self) else {
            return nil
        }
        
        var frame = subview.frame
        if subview.superview == nil {
            return frame
        }
        
        var superview = subview.superview
        while superview != self {
            frame = superview!.convert(frame, to: superview!.superview)
            if superview!.superview == nil {
                break
            } else {
                superview = superview!.superview
            }
        }
        
        return superview!.convert(frame, to: self)
    }

}

// usage:
let frame = firstView.getConvertedFrame(fromSubview: buttonView)

Frame: (X,Y,width,height).

Hence width and height wont change even wrt the super-super view. You can easily get the X, Y as following.

X = button.frame.origin.x + [button superview].frame.origin.x;
Y = button.frame.origin.y + [button superview].frame.origin.y;