45

In my app I want to create a new UIWindow over the main UIWindow, And I wrote as following, but it don't works. first, i create a UIWindow as the main window, and then make it key and visible, and then create a new UIWindow overlay, but nothing happens.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor redColor];
    ViewController *vc = [[ViewController alloc]initWithNibName:@"ViewController" bundle:nil];
    self.window.rootViewController = vc;
    [self.window makeKeyAndVisible];
    UIWindow *window1 = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
    window1.backgroundColor = [UIColor redColor];
    window1.windowLevel = UIWindowLevelAlert;
    [window1 makeKeyAndVisible];
    return YES;
}
CouchDeveloper
  • 18,174
  • 3
  • 45
  • 67
bohan
  • 1,659
  • 3
  • 17
  • 29

10 Answers10

68
UIWindow *window1 = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
window1.backgroundColor = [UIColor redColor];
window1.windowLevel = UIWindowLevelAlert;
[window1 makeKeyAndVisible];

Finally I know why it doesn't work, because window1 is a method var, and it will lost after the method executed. So I declare a new @property for it, as

@property (strong, nonatomic) UIWindow *window2;

and change the code like

UIWindow *window2 = [[UIWindow alloc] initWithFrame:CGRectMake(0, 80, 320, 320)];
window2.backgroundColor = [UIColor redColor];
window2.windowLevel = UIWindowLevelAlert;
self.window2 = window2;
[window2 makeKeyAndVisible];

it works!

shim
  • 9,289
  • 12
  • 69
  • 108
bohan
  • 1,659
  • 3
  • 17
  • 29
  • 3
    Why not: `self.window2 = [[UIWindow alloc] initWithFrame:CGRectMake(0, 80, 320, 320)]; self.window2.backgroundColor = [UIColor redColor]; self.window2.windowLevel = UIWindowLevelAlert; [self.window2 makeKeyAndVisible];` ? – atulkhatri Nov 25 '14 at 21:50
  • 2
    It's almost the same here, but usually – and mostly, especially in concurrent-threads situations – it's a good idea to fully populate object instance with all its properties and after that, assign to an owning property. In case some other thread would begin changing the `self.window2` properties while primary thread is in the middle of the block, you'd have no idea about final properties of an object assigned – could be a mixture of many different alternative states. – Michi Oct 29 '15 at 10:22
  • 1
    How do i dismiss that window ? – siva krishna Feb 15 '17 at 13:49
  • ten yrs later it's all different: https://noahgilmore.com/blog/uiwindowscene-black-screen/ – Fattie Jun 09 '22 at 16:58
13

Xcode 8 + Swift

class ViewController: UIViewController {
    var coveringWindow: UIWindow?
    
    func coverEverything() {
        coveringWindow = UIWindow(frame: (view.window?.frame)!)
        
        if let coveringWindow = coveringWindow {
            coveringWindow.windowLevel = UIWindowLevelAlert + 1
            coveringWindow.isHidden = false
        }
    }
}

According to the documentation, to receive events that do not have a relevant coordinate value, such as keyboard entry, make it key instead of merely ! isHidden:

coveringWindow.makeKeyAndVisible()

You can even control the transparency of its background, for a smoke effect:

coveringWindow.backgroundColor = UIColor(white: 0, alpha: 0.5)

Note that such window needs to handle orientation changes.

Community
  • 1
  • 1
SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
  • thanks for that. One thing ... _"Note that such window needs to handle orientation changes."_ it would seem that modern iOS now does that automatically. What do you think? Since perhaps iOS9 ? – Fattie Aug 16 '17 at 13:25
  • I tried it, and it seems not to work in iOS 13, the window just won't appear on the screen. And if I set ViewController as its root, I get error message "Manually adding the rootViewController's view to the view hierarchy is no longer supported. Please allow UIWindow to add the rootViewController's view to the view hierarchy itself." – joliejuly Nov 23 '19 at 21:32
13

If you are using a window scene try this:

private var overlayWindow: UIWindow!

if let currentWindowScene = UIApplication.shared.connectedScenes.first as?  UIWindowScene {
        overlayWindow = UIWindow(windowScene: currentWindowScene)
    }
overlayWindow.windowLevel = UIWindow.Level.alert
overlayWindow.rootViewController = UIViewController()//your controller or navController
overlayWindow.makeKeyAndVisible()
Nick Greg
  • 221
  • 4
  • 7
11

Your window1 object is a local variable, when the code runs out of this method, this object does not exist any more. Any UIWindow object we created will be add to the [[UIApplication sharedApplication] windows], but this array only keeps a weak reference to any UIWindow object, so it's up to your own code to keep the window object existing. Why apple implemented it like this, I guess, is [UIApplication sharedApplication] object exists as long as the app runs, doing so to avoid keeping the UIWindow objects which only needs to exist for a while living in the memory "forever".

What's more, your code could run with MRC.

Alex Zavatone
  • 4,106
  • 36
  • 54
Yulong Xiao
  • 191
  • 2
  • 4
5

SWIFT 5

In iOS13 and higher you must create UIWindow with windowScene: initializer as follows let overlayWindow = UIWindow(windowScene: YourScene). For lower iOS versions you should use frame: initializer as follows let overlayWindow = UIWindow(frame: YourFrame).

After creating UIWindow instance you can use code to display window as is written in @Nick Greg answer:

overlayWindow.windowLevel = UIWindow.Level.alert
overlayWindow.rootViewController = UIViewController()//your controller or navController
overlayWindow.makeKeyAndVisible()
Mr.SwiftOak
  • 1,469
  • 3
  • 8
  • 19
  • While not incorrect, this answer is identical to the NickGreg answer. To achieve an overlay window, simply **copy and paste the code form the NickGreg answer**. Nothing needs to be changed from the NickGreg answer. – Fattie Feb 20 '23 at 16:39
3

Swift 4

To avoid memory leak, I prefer to initialise my custom window in this way, as proposed by Apple :

If you want to provide a custom window for your app, you must implement the getter method of this property and use it to create and return your custom window.

Example:

var myCustomWindow: UIWindow? = CustomWindow(frame: UIScreen.main.bounds)

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    let mainController: MainViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as! MainViewController
    self.myCustomWindow?.rootViewController = mainController
    self.myCustomWindow?.makeKeyAndVisible()
}
drfalcoew
  • 615
  • 5
  • 14
1

if you just need to change shared window ViewController in swift 5

UIApplication.shared.keyWindow?.rootViewController = UINavigationController(rootViewController: yourViewController)
Mohamed Shaban
  • 2,263
  • 1
  • 15
  • 23
0

try adding a UIView on mainWindow not another UIWindow like...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor redColor];
    ViewController *vc = [[ViewController alloc]initWithNibName:@"ViewController" bundle:nil];
    self.window.rootViewController = vc;
    [self.window makeKeyAndVisible];
    UIView * viewAlert = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
    viewAlert.backgroundColor = [UIColor redColor];
    [self.window.rootViewController.view addSubView:viewAlert];
    /* or you can use following..
    [self.window addSubView:viewAlert];
    */
    [viewAlert release]; //FOR NON ARC
    return YES;
}
Nirav Gadhiya
  • 6,342
  • 2
  • 37
  • 76
0
func createAdsWindow(){
    let frame = CGRect.init(0, UIScreen.main.bounds.height - 60, UIScreen.main.bounds.width, 60)
    adsWindow = UIWindow.init(frame: frame)
    adsWindow!.backgroundColor = UIColor(colorBackground)
    let adsViewController = UIViewController.init()
    adsViewController.view.backgroundColor = UIColor.red
    adsWindow?.rootViewController = adsViewController
    adsWindow?.windowLevel = UIWindow.Level(rawValue: 2)
    adsWindow?.makeKeyAndVisible()
}
-1

In swift a new UIWindow can be added as follows..

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var viewController: ViewController?
    var navigationController: UINavigationController?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
        self.viewController = ViewController(nibName: "ViewController", bundle:NSBundle.mainBundle())
        self.navigationController = UINavigationController(rootViewController: self.viewController!)
        self.window!.rootViewController = self.navigationController
        //  self.window!.addSubview(self.viewController!.view)
        self.window!.makeKeyAndVisible()
        return true
    }

    //Other methods..
}
James Zaghini
  • 3,895
  • 4
  • 45
  • 61
Ajith K Jose
  • 131
  • 1
  • 9