SwiftKickMobile / SwiftMessages

A very flexible message bar for UIKit and SwiftUI.
MIT License
7.31k stars 743 forks source link

`windowLevel` in iOS 13 #335

Closed tchambers3 closed 4 years ago

tchambers3 commented 5 years ago

I'm trying to add a message that slides in over top the status bar. I'm using the .alert window level which works on iOS 12 but on iOS 13 this doesn't seem to be having the desired effect and the message comes in underneath the status bar.

wtmoose commented 5 years ago

Have you tried .statusBar?

tchambers3 commented 5 years ago

Yeah I tried .statusBar as well but this also comes in underneath the status bar.

wtmoose commented 5 years ago

Sounds like a radar is needed. I'll take a look when I get a chance.

wtmoose commented 5 years ago

I filed a bug for this. If anyone wants to file a duplicate bug report, you can use the following text and file attachment:

Title

UIWindow.windowLevel property broken on iOS 13

Description

Steps:

  1. Run attached Xcode project "WindowLevelBug" using Xcode 11 beta.
  2. Tap "Go".

Expected behavior: red window displayed above status bar Actual behavior: red window displayed below status bar

The "WindowLevelBug" app displays a window with its windowLevel property set to .alert. Per the API documentation, .alert means that "windows at this level appear on top of the status bar". And this was the case prior to iOS 13. On iOS 13, the window displays below the status bar.

This bug will affect many, many apps. For example, the open source library SwiftMessages utilizes alert-level windows and is used in thousands of apps.

WindowLevelBug.zip

wtmoose commented 4 years ago

An update. The response from Apple is that it is no longer possible to cover the status bar. They've suggested a workaround that I will look into:

Thanks for the feedback. As of iOS 13, it is no longer possible to place content above the status bar. Therefore, the documentation for UIWindowLevelAlert is incorrect.

I’ve cloned this radar so that the documentation will be updated, and we’ll consider what to do with levels like UIWindowLevelAlert going forward.

In the mean time, you can get the same effect by having the root view controller of your new window use view controller based status bar appearance API like prefersStatusBarHidden() or preferredStatusBarStyle().

I confirmed with your sample project (thanks!) that having the new window’s rootViewController return YES from prefersStatusBarHidden() doesn’t what you’d expect when the window is made and unhidden.

class StatusBarHidingViewController: UIViewController {
   override var prefersStatusBarHidden: Bool {
       return true
   }
}

class ViewController: UIViewController {

   let window = UIWindow()

   @IBAction func goTapped() {
       window.backgroundColor = .red
       window.windowLevel = .alert
       window.windowScene = view.window?.windowScene
       let viewController = StatusBarHidingViewController();
       window.rootViewController = viewController;
       window.makeKeyAndVisible()
   }
}

When the new window is made key and visible, the status bar goes away. Thanks again for the feedback.

wtmoose commented 4 years ago

Workaround is on the Swift 5.2 branch. It doesn't look as nice – the status bar visibly reappears when the message is dismissed – but it is the best that can be done.

wtmoose commented 4 years ago

Update. I removed the workaround and added an explicit prefersStatusBarHidden option to SwiftMessages.Config (similar to the existing preferredStatusBarStyle option).

tchambers3 commented 4 years ago

@wtmoose Gotcha. Thanks for looking into this!

wtmoose commented 4 years ago

The preferredStatusBarStyle option is included in 7.0.1 release.

rbarbish commented 4 years ago

Can you please post a gif/short video of what it looks like after this change please?

FIndustries commented 4 years ago

I don't know if I'm wrong but the prefersStatusBarHidden option doesn't seem to have any effect on iOS 13.

wtmoose commented 4 years ago

@FIndustries It only has an effect when you’re displaying a message in its own window.