2

I have implemented a popup UIView which I add to the topmost window via [[[[UIApplication sharedApplication] windows] lastObject] addSubview:popupView], so it will appear on top of everything even the keyboard. I need to ensure this popup view that I programmatically created will always remain centered on screen. I was attempting to add auto layout constraints, but it doesn't like the fact I'm trying to align with the topmost window. Could you let me know how I could accomplish this? Thank you.

This is what I have implemented, which will generate a (nicely detailed) error that states 'The view hierarchy is not prepared for the constraint ... the constraint's items must be descendants of that view':

    [popupView setTranslatesAutoresizingMaskIntoConstraints:NO];
    NSLayoutConstraint *cn = nil;
    cn = [NSLayoutConstraint constraintWithItem:popupView
                                      attribute:NSLayoutAttributeCenterX
                                      relatedBy:NSLayoutRelationEqual
                                         toItem:[[[UIApplication sharedApplication] windows] lastObject]
                                      attribute:NSLayoutAttributeCenterX
                                     multiplier:1.0
                                       constant:0];
    [popupView addConstraint:cn];
    cn = [NSLayoutConstraint constraintWithItem:popupView
                                      attribute:NSLayoutAttributeCenterY
                                      relatedBy:NSLayoutRelationEqual
                                         toItem:[[[UIApplication sharedApplication] windows] lastObject]
                                      attribute:NSLayoutAttributeCenterY
                                     multiplier:1.0
                                       constant:0];
    [popupView addConstraint:cn];
    cn = [NSLayoutConstraint constraintWithItem:popupView
                                      attribute:NSLayoutAttributeHeight
                                      relatedBy:NSLayoutRelationEqual
                                         toItem:nil
                                      attribute:NSLayoutAttributeNotAnAttribute
                                     multiplier:1
                                       constant:blockSize.height];
    [popupView addConstraint:cn];
    cn = [NSLayoutConstraint constraintWithItem:popupView
                                      attribute:NSLayoutAttributeWidth
                                      relatedBy:NSLayoutRelationEqual
                                         toItem:nil
                                      attribute:NSLayoutAttributeNotAnAttribute
                                     multiplier:1
                                       constant:blockSize.width];
    [popupView addConstraint: cn];
Jordan H
  • 52,571
  • 37
  • 201
  • 351

2 Answers2

2

Don't go sticking your view into a window that wasn't set up specifically to hold your views. You don't know what the real owner of that window might do, now or in a future version of iOS.

Create your own window and set its windowLevel high enough to be above the keyboard. Give the new window its own root view controller (so it will handle different orientations properly) and center your popup view inside that root view controller's view.

You will find lots of useful information in the answers to this question.

Community
  • 1
  • 1
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Thanks, though it seems that will significantly increase the complexity, because of these mentioned "issues": The window that is key receives all keyboard input, UIWindow covers everything, and UIWindow is always portrait-does not rotate-need to add a controller as the window's root and let it handle rotation. I need the UI to be fully responsive under this popup, should not cover system alerts (not sure if it would), and I need rotation. Could you elaborate on why using '[[[UIApplication sharedApplication] windows] lastObject]' is a bad idea? That was up-voted a bunch on another question. :p – Jordan H Apr 21 '14 at 06:02
  • I figured out why you said I shouldn't do that. While it worked on the simulator it didn't behave the same on a real device. I implemented your suggestion and now it's working beautifully. Thank you for suggesting the best approach for the future. I'd accept your answer but I did need rdelmar's answer as well. Too bad I can't accept both, hope you'll accept a +1. :) – Jordan H Apr 27 '14 at 05:03
1

It's fine to add the height and width constraints to popupView, but since popupView is a subview of the window, the centering constraints should be added to the window, not the popupView (and you need to add the popupView as a subview first, before you add the constraints).

rdelmar
  • 103,982
  • 12
  • 207
  • 218
  • 1
    @Joey, my answer was aimed at fixing your constraints problem, but Rob's answer is really the better way to go -- that approach will give you a more robust structure. – rdelmar Apr 21 '14 at 04:29
  • Thanks, but I thought I was already adding centering constraints to the window. view1(withItem) is the popupView and view2(toItem) is the window, and it doesn't matter if I swap those. – Jordan H Apr 21 '14 at 06:06
  • @Joey, but you added the constraint to popupView with [popupView addConstraint:cn]; That should be [[[[UIApplication sharedApplication] windows] lastObject] addConstraint:cn]; Constraints between two views in a hierarchy are always added to the superview, not the subview. – rdelmar Apr 21 '14 at 06:44