5
votes

I am presenting a UIImagePickerController to pick an image. My code is as simple as:

private lazy var imagePicker: UIImagePickerController = {
    let picker = UIImagePickerController()
    picker.navigationBar.isTranslucent = false
    return picker
}()

func presentPicker() {
    imagePicker.sourceType = .photoLibrary
    imagePicker.modalPresentationStyle = .fullScreen        
    present(self.imagePicker, animated: true, completion: nil)
}

I am setting picker.navigationBar.isTranslucent = false to have an opaque navigation bar in the picker controller. Unfortunately this doesn't work on iOS 13 and the navigation & status bars are transparent.

Partial solution:

private func setOpaqueNavigationiOS13() {
    UINavigationBar.appearance().backgroundColor = .white
}

private func resetNavigationiOS13() {
    UINavigationBar.appearance().backgroundColor = .clear
}

I call the above functions to make the navigation bar opaque and to reset it when dismissing the picker. This makes the navigation bar opaque but the status bar is transparent. I can implement a hack to make the status bar opaque as well but I guess there should be a simpler solution.

EDIT: I've also tried setting the navigation bar's appearance by the new UINavigationBarAppearance:

if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    appearance.backgroundColor = .white
    UINavigationBar.appearance().standardAppearance = appearance
    UINavigationBar.appearance().compactAppearance = appearance
    UINavigationBar.appearance().scrollEdgeAppearance = appearance
}

Or:

if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    appearance.backgroundColor = .white
    imagePicker.navigationBar.standardAppearance = appearance
    imagePicker.navigationBar.compactAppearance = appearance
    imagePicker.navigationBar.scrollEdgeAppearance = appearance
}

Anyone that came up with a fix? Thanks

2
"This makes the navigation bar opaque but the status bar is transparent" That's correct; you should never set a navigation bar's background color like that. In iOS 13, use the new UIBarAppearance architecture and leave the isTranslucent property alone.matt

2 Answers

0
votes

I am posting my solution in case it's helpful for others. Although matt's answer is totally correct, it applies when all of you nav bar setup is done through UINavigationBarAppearance. This did not help in my case because I've already done this in AppDelegate:

// Make navigation bar transparent throughout whole app
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)

And as my app showcases a lot of nav bar styling and I needed a quick fix just to satisfy iOS 13 changes I just did this:

// Set nav bar to opaque 
if #available(iOS 13.0, *) {
    UINavigationBar.appearance().setBackgroundImage(nil, for: .default)
}

Just don't forget to bring it back to transparent if needed.

-1
votes

In iOS 13, the correct way to customize the look of a navigation bar is through the UIBarAppearance architecture (the navigation bar's standardAppearance and so forth). You can apply this directly to the navigation bar or use the UINavigationBar appearance proxy.