How can I ensure iOS 13 modal view controllers present the right status bar colour? - ios

With the new iOS 13 view controller changes, view controllers are being presented that don't cover the whole screen. They instead leave a black space at the top. However, the system status bar is not changing colour automatically. When I present a modal view controller, the status bar is staying with now-invisible black text (and a green battery which looks super weird in the middle of nowhere).
How do I make the bar behave in the same way as within Apple's apps, where the bar animates to different colour when a modal popup appears?
I've tried setting modalPresentationCapturesStatusBarAppearance to true on my modal controllers, to no luck.
The bar in my presenting view controller is a UINavigationBar, and is not part of a navigation controller. The presenting VC is its delegate, and I've overridden position(for bar: UIBarPositioning) to return .topAttached.
I've tried presenting the modal with .modalPresentationStyle = .formSheet and without setting .modalPresentationStyle at all. Neither worked.
Broken:
The presenting VC:
Expected Behaviour:

Two things:
The modal view controllers need to have VC.modalPresentationCapturesStatusBarAppearance = false. This is the default but if, like me, you set it to something else, make sure it's false!
You need to ensure that View controller-based status bar appearance in your info.plist is set to YES. I'd messed around with it in an attempt to make my status bar the right colour but having it set to NO was a problem.

Related

Can see Status Bar space but not information in iOS Swift

I add Navigation Controller(2nd View) and add one UIViewController(3rd View) as root view controller.
And then I connect segue to Navigation Controller(2nd View) from anther UIViewController(1st View).
So I can see navigation Bar with Status bar space when the view is presented.
But the information like Carriers, batteries, time information are not shown in Status Bar.
(I changed navigation Color to pink for showing you the problem.
The blue part is title view for navigation bar.)
So I tried 2 solutions.
First, I thought StatusBar Color problem. But it was not.
UIApplication.shared.statusBarStyle = .default
Second, I tried following code for showing. It was not also.
override var prefersStatusBarHidden: Bool {
return false
}
and
UIApplication.shared.setStatusBarHidden(false, with: UIStatusBarAnimation.none)
I need to solve this not-showing problem with status Bar.
I can see status Bar space but not information.
There are lots of ways to toggle the color and visibility of the status bar in iOS.
Similar question with possible correct answers for you:
How to change Status Bar text color in iOS 7
In short, if you want to toggle it between every screens, follow these steps:
In your info.plist, add this new key:
View controller-based status bar appearance and value should be NO.
In your viewWillAppear, toggle the status bar with the code you have posted:
UIApplication.shared.statusBarStyle = .lightContent - white
or
UIApplication.shared.statusBarStyle = .default - black
Edit:
Initial ViewController --> Present Modally --> NavigationController + ViewController.
This is how you set up your screens, right?. If so,
You can setup the status bar in your NavigationController properties in your Interface Builder.
And toggle the visibility and/or color of your status bar in side the viewWillAppear of your 3rd ViewController.
I suggest you check out Debug View Hierarchy.
Based on my experiences in previous projects, if I can't come up with code-based solutions on UI-related problems the simplest debugging technique that I can do is check the view hierarchy during run time.
See if the Navigation Controller View blocks the Main View which can possibly hide the status bar and if yes, work your way on solving it.
I hope it helps.

iOS Swift: Incorrect Navigation Bar Appearing

The incorrect navigation bar is appearing on my Table View Controller screen (see Storyboard Below).
I would like what's displayed on the storyboard to be my navigation bar (i.e. with "Main Feed" title and Sign Out button on the top right). However, this is what I'm actually getting -
There are two issues here: 1) The incorrect navigation bar is displaying (this one has a login back button); 2) the first few table view cells are placed underneath the nav bar vs. under it.
This happened after I embedded the Table View controller in the Tab Bar Controller. I want a bottom tab bar in the main portion of my application hence the reason why I added the Tab Bar Controller. Any suggestions on how to fix this? Rather than using the Tab Bar Controller in storyboard, is there a way to do this programatically? Thanks!
The navigation bar that you are seeing on top of the stack is the navigation bar from the UITabBarController itself, that is why you are seeing the back button show "login". There's a few ways to work around this, programmatically:
When you initialize the UITabBarController, set it's navigationController's navigation bar property to "hidden"
Go through each view controller form the beginning of your app up to where you first see this problem and in the "init" method of the viewController you are testing, set the navigationbar to hidden. Something like, self.navigationController?.navigationBar.hidden = true;
This is how you can "debug" this issue, but it's going to take some tweaking to get it right.

set up status bar text color of a UINavigationController that is presented modally from a modal

I have a modal view controller whose navigation controller's bar style is "UIStatusBarStyleBlack", so its status bar text color is white.
However, if I present a UINavigationController modally from here and I want it to be have a bar style of "UIStatusBarStyleDefault", I can't control the status bar text color.
I've tried everything suggested on SO (subclass, extensions, etc), but none of the solutions take this scenario into account (modal on a modal).
EDIT: This seems to only be the issue whenever it is presented from a non-fullscreen modal. So, if the first modal was fullscreen, everything works. But if it was a form sheet or popover on iPad, then the modal presented from there won't update the status bar color.
I think the problem is that you are presenting your view controller instead of a navigation controller.
First you need to create a navigation controller with root view controller as your view controller and then present that navigation controller.
If this is not the case then kindly post some code which shows how exactly you are currently approaching the case.

UIImagePickerController vs status bar iOS8

I'm subclassing UIImagePickerController in attempt to override its default status bar behavior and having mixed results. My app uses view controller-based status bar appearance.
Without subclassing, I'm finding that it changes the status bar style to Default (dark) when the picker is dismissed, and nothing I've tried yet in my initial view controller is fixing it. Also, when the picker hides the status bar while being presented, sliding it upwards, the initial view controller's navigation bar slides up with it from height 64 to 44.
So I want my UIImagePickerController subclass to keep the status bar style as LightContent and, in an attempt to work-around the sliding navigation bar, keep the status bar showing while presenting the picker, then hide it on viewDidAppear:.
The first interesting thing is that preferredStatusBarStyle and prefersStatusBarHidden in my picker subclass weren't called at all until I also overrode childViewControllerForStatusBarStyle and childViewControllerForStatusBarHidden to return nil. This seems to indicate that normally, a UIImagePickerController is overriding those, probably to return an internal child view controller. Looking at the view hierarchy in viewDidAppear:, there's certainly a child PLImagePickerCameraView and its likely there's a controller to go with it. Sadly we cannot override this controller.
Overriding those childViewControllerFor... methods, preferredStatusBarStyle and prefersStatusBarHidden do get called in-between viewWillAppear: and viewDidAppear:, and can indeed keep the status bar visible and LightContent. The second interesting thing though, is that before the presentViewController animation the status bar briefly blinks dark. No amount of extra calls to setNeedsStatusBarAppearanceUpdate in viewWillAppear: or other places such as viewDidLoad: seem to prevent that.
The third interesting thing is that the bar style is still getting set to dark during dismissal, and no extra calls to setNeedsStatusBarAppearanceUpdate in the picker's viewWillDisappear: or viewDidDisappear: seem to prevent that.
tl;dr -- I've found that overriding UIImagePickerController to hide & show the status bar on demand to work pretty well, but setting the bar style is problematic. Something in the picker class or UINavigationController itself is automatically preferring the Default bar style, and when its switched to that on dismissal, it seems difficult to switch it back.
I've seen the Question UIImagePickerController breaks status bar appearance, and nothing I've seen there has helped yet, and iOS8.1 doesn't fix it. I was sure that setting the picker's navigationBar.barStyle to black would do it, but no dice. Any ideas anybody?
(Also, any tips on preventing a UINavigationController's navigation bar from sliding up to 44 height when the status bar is hidden would be useful thx)

Transitioning between transparent navigation bar to translucent

In Apple's recently released Remote app I noticed the way in which the navigation bar behaves is unique and I haven't been able reproduce it. When popping the Now Playing view controller the navigation bar remains transparent for the Now Playing view controller and the navigation bar for the library view controller also stays translucent (Screenshot 1). I'm trying to figure out if they are using two navigation controllers or only one. Personally I feel they're using just one for two reasons (1) the interactive pop gesture is enabled; (2) when you press the 'Now Playing' button in the library view controller, just before the now playing screen has finished 'push view controller' animation the navigation bar becomes transparent (Screenshot 2). This is the behaviour I experience when pushing my view controller (which sets the navigation bar to transparent). So my question is: How does Apple present both navigation bars of the two view controllers as if they were individual (as with Screenshot 1), even the bar buttons, navigation title etc... are 100% in opacity when switching (usually when pushing/popping the buttons and titles of the previous view controller fade as the new controller is being pushed). I've tried playing around with the bar tint colour in viewDidAppear and viewWillAppear in both view controllers but cannot reproduce the same behaviour, and cannot prevent the bar buttons from fading.
Gosh I hope I've explained this well, I get confused just thinking about it!
Screenshot 1 (Popping):
Screenshot 2 (Pushing):
I just downloaded the application to make sure. Two different navigation bars are used. You can see this by using the interactive pop gesture. Notice how the navigation bar on the bottom view controller slides in and out. During normal push and pop transitions, the navigation items just fade in and out on the existing bar, while the bar is stationary. This is what happens up until the point where the now playing view controller is pushed.
If you look quickly, during the now playing view controller animation, you can see the bottom navigation bar disappear.
From my experience with UIKit behavior and what I see in the app, here is what I think happens:
album_vc = the bottom, list view controller
nowplaying_vc = the top view controller
On nowplaying_vc's viewWillAppear:
Set the navigation bar to hidden using [self.navigationController setNavigationBarHidden:YES animated:YES];. Since this is in animation block, this will make the navigation bar slide out during the push animation.
Set [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; Pretty sure about this, because notice there is no animation in the transition of the status bar styles. It just becomes white.
On nowplaying_vc's viewWillDisappear:
Set the navigation bar to shown using [self.navigationController setNavigationBarHidden:NO animated:YES];. Since this is in animation block, this will make the navigation bar slide in during the pop animation.
Set [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault; Again, notice how during interactive pop gesture, the status bar just changes with no animation.
To achieve the transparent look of the navigation bar of nowplaying_vc, you can use an empty image ([UIImage alloc]) with setBackgroundImage:forBarPosition:barMetrics:.
Since the application does not rotate, we can't be sure if the navigation bar on nowplaying_vc is part of another navigation controller or just a navigation bar on the top with a position of UIBarPositionTopAttached. For all we know, there isn't even a navigation bar there but just a back chevron image view (back bar button is comprised of an image view and a button).
I think the status bar style is changed in viewWillAppear: and viewWillDisappear: due to the unnatural feel there is during interactive pop gesture. I would recommend using an animated transition, or even better, use the new view controller-based status bar style, which the system animates transitions by itself.
Update for modern API:
You should use the animateAlongsideTransition:completion: or animateAlongsideTransitionInView:animation:completion: API, rather than relying on the implicit animations of viewWillAppear: and viewWillDisappear:.
Instead of hiding and showing the navigation bar, you can update the alpha for the navigation bar. It will animate smoothly during the transition. For the view controller with transparent nav bar, instead of modifying the nav bar, create a navbar (or just the back button and title etc.) manually in the second controller's view. We will then hide the navbar when transitioning from first view controller to the second one.
On your first controller's viewWillDisappear and on your second view controller's viewWillAppear:, set the navigation bar alpha to zero using self.navigationController.navigationBar.alpha = 0;. Since this is in animation block, this will make the navigation bar disappear during the push animation.
Set the alpha back to one in first controller's viewWillAppear and second controller viewWillDisappear.

Resources