Search code examples
iosswiftpopover

Why does the status bar appear when popoverPresentationController is called in Swift?


In my app you can tap a UIButton and a popover pops up and shows the Photo Library of the user.

I am using this code to make that happen:

        let picker = UIImagePickerController()
        picker.allowsEditing = false
        picker.sourceType = .PhotoLibrary
        picker.modalPresentationStyle = .Popover
        self.presentViewController(picker, animated: true, completion: nil)
        picker.popoverPresentationController?.sourceRect = CGRectMake(600,180,0,0)
        picker.popoverPresentationController?.sourceView = self.view

The code above works fine and does shows the popover to the user. However, it also shows a white status bar.

I tried hiding the status bar in many ways:

UIApplication.sharedApplication().statusBarHidden = true

I made sure this String in the info.plist file was set to NO: View controller-based status bar appearance.

I also have this code in my class:

    override func prefersStatusBarHidden() -> Bool {
    return true
}

The UIViewController Attributes Inspector looks like this:

Imgur

Unluckily, the popover still shows the status bar. Why? How can I fix that?


Solution

  • The ImagePickerController is very keen on displaying a status bar, regardless of your app settings. I have managed to surpress it by subclassing ImagePickerController and overriding viewWillAppear and prefersStatusBarHidden:

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.setNeedsStatusBarAppearanceUpdate()
    }
    
    override func prefersStatusBarHidden() -> Bool {
        return true
    }
    

    This solution is fine if your imagePicker sourceType is .SavedPhotosAlbum but doesn't work so well if sourceType is .PhotoLibrary. The latter source type presents you with navigation options within the imagePickerController. While the first screen's status bar is under your control, you lose that control as soon as you navigate to Moments or Camera Roll. The status bar reappears and - worse - animation transitions between the viewControllers are really messed up. You can get more control over the process by intercepting UINavigationController delegate methods (UIImagePickerController is a subclass of UINavigationController), but I have only succeeded well with soureType = .SavedPhotosAlbum

    EDIT

    you may also have to include this:

    override func childViewControllerForStatusBarHidden() -> UIViewController? {
        return nil;
    }
    

    for completely mysterious reasons!

    EDIT2

    Putting it all together...

    class MyImagePickerController: UIImagePickerController {
    
        override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(animated)
            self.setNeedsStatusBarAppearanceUpdate()
        }
    
        override func prefersStatusBarHidden() -> Bool {
            return true
        }
    
        override func childViewControllerForStatusBarHidden() -> UIViewController? {
            return nil;
        }
    
    }
    

    Then you change this line:

    let picker = UIImagePickerController()
    

    to:

    let picker = MyImagePickerController()