Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

convertRect: toView: returns double size and twice the distance from the origin

I pass in an image view to an init method that needs the size of the image view. Then call convertRect:toView:

- (id) initWithImageView:(UIImageView*) imageView {
    self = [super init];
    if (self) {
        CGRect imageViewFrame = [[imageView superview] convertRect: imageView.frame toView: self.view];
    }
}

Which was called with:

MyViewController *viewController = [[MyViewController alloc] initWithImageView:imageView];
viewController.delegate = self;
[self.tabBarController presentViewController:viewController animated:NO completion:nil];

imageViewFrame is then

(origin = (x = 0, y = -120.22867049625003), size = (width = 750, height = 750))

the imageView has a frame of

frame = (0 -60.1143; 375 375);

and it's super view is has a frame of

frame = (0 0; 375 254.5);

Why would it be scaled up x2 ?

Further testing on iPhone 6 plus (3x) simulator makes imageViewFrame

(origin = (x = 0, y = -199.30952358000002), size = (width = 1242, height = 1242))

The first tests were done on iPhone 6 simulator (2x). Why is convertRect:toView: working in pixels and not points?

like image 746
richy Avatar asked Oct 19 '22 13:10

richy


2 Answers

In your -initWithImageView:, your self.view has not been generated yet, you can try to cache the imageView temporary, and do the rect converting action in -viewDidLoad instead:

// If you don't user Interface Builder
- (void)loadView
{
   CGRect frame = <your_view_frame>;
   UIView * view = [[UIView alloc] initWithFrame:frame];
   self.view = view;
}

- (void)viewDidLoad
{
  [super viewDidLoad];

  CGRect imageViewFrame = [[imageView superview] convertRect:imageView.frame toView:self.view];
  ...
}

Edit

As the doc said for -convertRect:toView:'s view param:

The view that is the target of the conversion operation. If view is nil, this method instead converts to window base coordinates. Otherwise, both view and the receiver must belong to the same UIWindow object.

If you persist in doing in -initWithImageView method, declare a custom view iVar, alloc & init in your -initWithImageView method, then in -loadView, assign the iVar to self.view. And of course, the way you used to convert rect in -initWithImageView should be

CGRect frame = <your_view_frame>;
_iVarView = [[UIView alloc] initWithFrame:frame];
CGRect imageViewFrame = [[imageView superview] convertRect:imageView.frame
                                                    toView:_iVarView];

In -loadView:

- (void)loadView
{
   self.view = _iVarView;
}

But it's not recommend to do it in this way, I suggest you init UI in the right methods of view's life loop.

like image 59
Kjuly Avatar answered Oct 30 '22 14:10

Kjuly


Here is a correct method: SWIFT:

extension UIView {

    func convertRectCorrectly(rect: CGRect, toView view: UIView) -> CGRect {
        if UIScreen.mainScreen().scale == 1 {
            return self.convertRect(rect, toView: view)
        }
        else if self == view {
            return rect
        }
        else {
            var rectInParent = self.convertRect(rect, toView: self.superview)
            rectInParent.origin.x /= UIScreen.mainScreen().scale
            rectInParent.origin.y /= UIScreen.mainScreen().scale
            let superViewRect = self.superview!.convertRectCorrectly(self.superview!.frame, toView: view)
            rectInParent.origin.x += superViewRect.origin.x
            rectInParent.origin.y += superViewRect.origin.y
            return rectInParent
        }
    }
}
like image 29
Alexander Volkov Avatar answered Oct 30 '22 15:10

Alexander Volkov