Get position of UIView in respect to its superview's superview
Asked Answered
M

8

118

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"?

Mor answered 10/7, 2013 at 13:46 Comment(0)
P
230

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

Pivot answered 10/7, 2013 at 13:50 Comment(2)
To add to this, if your view is not always in the same view (say, if you're using this in a function) you can put '...fromView:[button superview]];'Kerrison
Is there a way of doing this in SwiftUI?Baseless
D
60

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)
Dimeter answered 15/4, 2018 at 10:42 Comment(0)
M
25

Updated for Swift 3

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

        print(frame)
    }

enter image description here

Makebelieve answered 12/8, 2017 at 6:43 Comment(0)
L
14

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)
Lupien answered 29/7, 2019 at 20:51 Comment(1)
THIS IS PERFERCT SOLUTION! THANKS A LOT!Marcelina
A
8

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;
Acreinch answered 10/7, 2013 at 13:52 Comment(1)
But why i am getting the X, Y value in so high amount like when my X was 0,0 then i am getting with your lines of code as; 180224 or so?Ridinger
T
5

If there are multiple views stacked and you don't need (or want) to know any possible views between the views you are interested in, you could do this:

static func getConvertedPoint(_ targetView: UIView, baseView: UIView)->CGPoint{
    var pnt = targetView.frame.origin
    if nil == targetView.superview{
        return pnt
    }
    var superView = targetView.superview
    while superView != baseView{
        pnt = superView!.convert(pnt, to: superView!.superview)
        if nil == superView!.superview{
            break
        }else{
            superView = superView!.superview
        }
    }
    return superView!.convert(pnt, to: baseView)
}

where targetView would be the Button, baseView would be the ViewController.view.
What this function is trying to do is the following:
If targetView has no super view, it's current coordinate is returned.
If targetView's super view is not the baseView (i.e. there are other views between the button and viewcontroller.view), a converted coordinate is retrieved and passed to the next superview.
It continues to do the same through the stack of views moving towards the baseView.
Once it reaches the baseView, it does one last conversion and returns it.
Note: it doesn't handle a situation where targetView is positioned under the baseView.

Torsibility answered 24/1, 2019 at 15:57 Comment(0)
B
3

You can easily get the super-super view as following.

secondView -> [button superview]
firstView -> [[button superview] superview]

Then, You can get the position of the button..

You can use this:

xPosition = [[button superview] superview].frame.origin.x;
yPosition = [[button superview] superview].frame.origin.y;
Bilinear answered 11/12, 2018 at 1:8 Comment(1)
Adding some explanation would make this answer more useful.Vadnais
S
2

Please note that the following code works regardless of how deep (nested) is the view you need the location for in the view hierarchy.

Let's assume that you need the location of myView which is inside myViewsContainer and which is really deep in the view hierarchy, just follow the following sequence.

let myViewLocation = myViewsContainer.convert(myView.center, to: self.view)
  • myViewsContainer: the view container where the view you need the location for is located.

  • myView: the view you need the location for.

  • self.view : the main view

Spermatocyte answered 27/11, 2020 at 4:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.