Nam
Nam

Reputation: 1876

UIView absolute screen point

Is there an easy way of getting the absolute point of UIView? By absolute I mean the location of the UIView relative to 1024x768 on an iPad?

I need an easy way because I have a UIButton inside a UITableViewCell inside a UITableView inside a view presented by a viewcontroller that is a child of another view controller repeating to the fifth or sixth view controller. And due to this complex design I need the absolute rect of the UIButton so I can display an UIActionSheet on the "main" viewcontroller.

Upvotes: 2

Views: 14497

Answers (7)

Abu-Bakr
Abu-Bakr

Reputation: 441

You can achieve the absolute frame of any view using the following method:

func getAbsoluteFrame(of view: UIView, rootViewController: UIViewController) -> CGRect {
    guard let parentView = view.superview else {
        print("Super view of this view is nil")
        return view.frame
    }
    
    return rootViewController.view.convert(view.frame, from: parentView)
}

You can get the rootViewController like this:

let rootViewController = UIApplication.shared.keyWindow!.rootViewController

Upvotes: 0

Warren Stringer
Warren Stringer

Reputation: 1883

Swift 4 convert that seems to work for a more than two levels of subviews:

// given that myView is in hierarchy of rootView, either
// have rootView convert its origin from myView, or
// have myView convert rootView's origin to rootView

rootView.convert(rootView.origin, from: myView)
var absView = myView.convert(rootView.origin, to: rootView)

I found the convert routine somewhat confusing. So, I brute force tested all the possible combinations with 5 levels of views. With the results posted on github

[Edit] When rootView is a UITableView, adjust for contentOffset:

 if let tableView = rootView as? UITableView {
        absView.y -= tableView.contentOffset.y
 }

Upvotes: 1

Aaron Bratcher
Aaron Bratcher

Reputation: 6471

To convert from a view's local frame or path to SCREEN coordinates, use the built-in converters:

UIAccessibilityConvertPathToScreenCoordinates

or

UIAccessibilityConvertFrameToScreenCoordinates

This does return a path or rect, but you can extract points from those.

Upvotes: 0

Earl Grey
Earl Grey

Reputation: 7466

So, we have a let's call it small view that has a certain point inside it. That point has local coordinates relative to its parent view that is small view. Now, we want to know, what would be the coordinates of that point if it would stay in the same spot on the screen, but it would be part of the root view. (this effectively gives us the coordinates relative to the whole screen.)

You will calculate the global coordinates of that point

CGPoint globalCoordinates = [self.smallView convertPoint:localCoordinatesOfThePoint 
                                                  toView:self.view];

localCoordinatesOfThePoint is also a CGPoint structure.

Another scenario

is when you have the whole screen covered with root view, this has a large view, (still smaller than the root view though), and this large view has a small view as a subview inside it.

You will calculate the position of the small view's tip

CGPoint originOnScreen = [self.smallView convertPoint:self.smallview.origin 
                                               toView:self.view];

self.smallview.origin is a CGPoint relative to Large view. Thus, we calculate, what would be its coordinates if this point (it's the top-left tip of small view really) would be inside the root view.

CATCH

If the root view is not full screen, than instead of root view ,we need to get a reference to the main window as this will be our view against which we calculate coordinates now.

we have to

#import "AppDelegate.h"

in our class where we calculate and then pass the window property as the reference view. It is guaranteed that window covers the screen and UIWindow is a subclass of UIView. So it just works.

AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];

CGPoint originOnScreen = [self.smallView convertPoint:self.smallview.origin 
                                               toView:appDelegate.window];

Upvotes: 9

Nam
Nam

Reputation: 1876

So I ended up using UITapGestureRecognizer instead and calculating the position like this:

    CGPoint gestureViewLocation = [gesture locationInView:gesture.view];
    CGPoint absoluteLocation = [gesture locationInView:self.parentViewController.view];
    CGRect fromRect = CGRectMake(absoluteLocation.x-gestureViewLocation.x, //subtract to we get point relative to gesture view
                                 absoluteLocation.y-gestureViewLocation.y, //subtract to we get point relative to gesture view
                                 gesture.view.frame.size.width,
                                 gesture.view.frame.size.height);

Upvotes: -1

YYfim
YYfim

Reputation: 1412

If you want to get the coordinates of a CGPoint/ CGRect in a certain UIView you can use the UIView methods

- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view

or for CGRect

- (CGRect)convertRect:(CGRect)rect toView:(UIView *)view

in the first argument put the CGPoint/CGRect you want to convert and in the second put the UIView you want to convert to

Upvotes: 1

random
random

Reputation: 8608

What you are looking for is:

- (CGPoint)convertPoint:(CGPoint)point
                 toView:(UIView *)view

This will converts a point from the receiver’s coordinate system (your button) to that of the specified view (top level view).

Documentation

Upvotes: 1

Related Questions