How to use modalPresentationCapturesStatusBarAppearance = NO with a custom UIPresentationController? - ios

I have a custom UIPresentationController and overrides frameOfPresentedViewInContainerView for a custom viewController presentation. Everything works fine, except for the status bar.
I do not want the status bar to change appearance at all – it should just stay however it looked before. Now the Apple Documentation: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/#//apple_ref/occ/instp/UIViewController/modalPresentationCapturesStatusBarAppearance says if modalPresentationStyle is not UIModalPresentationFullScreen OR modalPresentationCapturesStatusBarAppearance is NO, i should be fine and the status bar should not change.
With this code:
- (BOOL)prefersStatusBarHidden {
NSLog(
#"prefersStatusBarHidden was called %d %ld",
self.modalPresentationCapturesStatusBarAppearance,
(long)self.modalPresentationStyle
);
return YES;
}
I can see that prefersStatusBarHidden is called, even if modalPresentationCapturesStatusBarAppearance is NO (displays as 0) and modalPresentationStyle is UIModalPresentationCustom (displays as 4).
Obviously, that's the reason the status bar changes when presenting the viewController.
But why?
My thought on this is that iOS thinks that the viewController is presented in fullscreen even though it is not.
I discovered UIPresentationController's property shouldPresentInFullscreen – it returns YES by default. Returning NO doesn't help at all, so i don't understand what that property even does... It has literally no effect. The same applies to the presentationStyle property – I don't see any effect when changing it. I would have expected the presentationStyle property to be "redirected" to the viewControllers modalPresentationStyle property, but that stays at UIModalPresentationCustom, which it has to be to initiate the custom presentation in the first place.
So, my questions are: Does anybody know how to just keep the status bar as it is with a custom UIPresentationController – and can somebody explain the shouldPresentInFullscreen and presentationStyle properties?
Thank you! :)

Try implementing childViewControllerForStatusBarStyle: and return nil for it in the class invoking your UIPresentationController, usually a UINavigationController.
This is what I do in Swift when I don't want a child VC to interfere with my wisely chosen Status Bar Style:
override func childViewControllerForStatusBarStyle() -> UIViewController? {
return nil // ignore childs and let this Navigation Controller handle the StatusBar style
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent // or .Default depending on your Style
}
This requires iOS8 and newer and is only usable if you are setting the key UIViewControllerBasedStatusBarAppearance in your Info.plist to YES.
Bonus: If this does not help in the caller, use it in the shown Ccontroller. I checked my projects, in one of them it's also in the NavigationController shown as PopOver and working fine as of today.

Related

Style status bar when navigation bar is hidden

I know that with UIKit usually you just override:
override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent }
in your UIViewController (or UINavigationController if it exists). It works perfectly fine.
However, I run into a problem when I perform this:
navigationController?.setNavigationBarHidden(true, animated: true)
Now, I can see no navigation bar, which is expected and perfectly fine. However, I see the status bar with the dark font, what is unexpected (my navigation controller overrides above property and it works properly when the navigation bar is not hidden). I want to see the status bar, but I want it in a light font. Navigation controller from this point does not listen to preferredStatusBarStyle, so I can't set it up this way.
Is there any way to display .lightContent status bar style when the navigation bar is hidden..?
The end effect is visible on the screenshot. If you zoom in, you can see dark letters & battery on dark background.
PS. Please do not post answers only about SwiftUI (here we support old iOS as well) & deprecated stuff.
Found a solution to make SDK ask for style when there is a navigation controller and the navigation bar is hidden but the status bar is shown.
In UINavigationController subclass, you need to override
override var childForStatusBarStyle: UIViewController? { return viewControllers.last }
And then inside these controllers, you can specify
override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent }
For some reason, if the navigation bar is hidden, iOS SDK does not ask navigation controller for preferredStatusBarStyle. However, it still asks childForStatusBarStyle and we've got an issue fixed :)
Try to set your status bar style to light
After that set View controller-based status bar appearance to NO in your info.plist
UPDATE
If you want the light content only in one view you can try to override the user interface style to dark in viewDidLoad
if #available(iOS 13.0, *) {
self.overrideUserInterfaceStyle = .dark
}

Swift 3 - how to hide Status Bar when using Over Full Screen

I'm developing a swift app and I can't find how to hide Status Bar when I use Over Full Screen presentation on my modal.
However, I put this line of code in my Modal View Controller :
override var prefersStatusBarHidden: Bool {
return true
}
And it is working if I create a segue which is not a modal, or if I create a segue which is a modal but not with Over Full Screen presentation.
I searched on internet how to fix it, and I found people who had the same problem but there had no solution.
Also, I can't change the color of my Status Bar when I'm using Over Full Screen option. I don't understand why? I think it's related.
Thanks for your help!
To hide the status bar when doing an over full screen modal, you need to set this in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
modalPresentationCapturesStatusBarAppearance = true
}
Then do the standard method to hide the status bar:
override var prefersStatusBarHidden: Bool {
return true
}
We can override preferredStatusBarStyle from individual view controller as you have done correctly.
Along with this, insert a new key named “View controller-based status bar appearance” and set the value to NO in your info.plist.
By disabling the “View controller-based status bar appearance”, you can set the status bar style by using the following code.
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; //objective-c
Hence it should solve "I can't change the color of my Status Bar when I'm using Over Full Screen option"

Hiding status bar not working Swift 3, Xcode 8.0

Set Target/General/Deployment info to Hide status bar.
Set None for Status Bar in VCs in storyboards.
Added the following code to all VCs.
override var prefersStatusBarHidden: Bool {
return true
}
Briefly hides status bar but immediately reappears.
Only the prefersStatusBarHidden of the root-level view controller matters — here, the split view controller. The split view controller wants a status bar; it gets a status bar. That is all that matters.
You could try subclassing UISplitViewController, setting prefersStatusBarHidden in your subclass, and using that subclass in the app.

Changing the statusBar color to light in specific ViewController

I've researched the internet and found out how i'm suppose to do however when i try it nothing seem to happen. it is still dark? what am i doing wrong?
Set View controller-based status bar appearance to YES
set self.setNeedsStatusBarAppearanceUpdate() in ViewDidLoad
add below code.
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent
}
First Set View controller-based status bar appearance to NO.
and can set like this
navigationViewController.navigationBar.barStyle = UIBarStyle. LightContent
It's possible something else is overriding your setting. For example, if you're in a navigation controller, you might find you need to subclass UINavigationController to have that set the status bar colour.
Use it in viewWillAppear
UIApplication.sharedApplication().setStatusBarStyle(.LightContent, animated: false)

Under iOS 7, how do I hide and show status bar on the fly (whenever I want to)

Say a user is in a View Controller and wants to enter a "full screen" type mode where the status bar is hidden, under iOS 6 it was a simple method call to hide/show the status bar, but no matter what it seems to persist under iOS 7.
I've seen solutions like this:
- (BOOL)prefersStatusBarHidden {
return YES;
}
But that doesn't allow it to be toggled at runtime. (It doesn't accept any arguments.)
In my info.plist I have View controller-based status bar appearance set to NO.
I'm at wits end. How do I hide it?
Swift 4
show:
(UIApplication.shared.value(forKey: "statusBarWindow") as? UIWindow)?.isHidden = false
hide:
(UIApplication.shared.value(forKey: "statusBarWindow") as? UIWindow)?.isHidden = true
Objective-c
Well here's one way of doing this:
in myViewController.h
#interface myViewController : UIViewController {
BOOL shouldHideStatusBar;
}
Then in myViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
shouldHideStatusBar = YES;
}
- (BOOL)prefersStatusBarHidden {
return shouldHideStatusBar;
}
and let's say when I touch the screen it should show the status bar now. You'll need to call: setNeedsStatusBarAppearanceUpdate specifically to get this working and then a switch (bool in this case) to show/hide.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
shouldHideStatusBar = (shouldHideStatusBar)? NO: YES;
[self setNeedsStatusBarAppearanceUpdate];
}
setNeedsStatusBarAppearanceUpdate
This should be called whenever the return values for the view
controller's status bar attributes have changed. If it is called from
within an animation block, the changes will be animated along with the
rest of the animation block.
prefersStatusBarHidden:
Return Value A Boolean value of YES specifies the status bar should be
hidden. Default value is NO.
Discussion If you change the return value for this method, call the
setNeedsStatusBarAppearanceUpdate method.
To specify that a child view controller should control preferred
status bar hidden/unhidden state, implement the
childViewControllerForStatusBarHidden method.
If you plan on your app working with iOS 6 as well might want to look at this post
I was having trouble with some of the other answers in iOS 8 so I did a little more research and found: [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:NO];. You can then enable/disable the animation.
Recommendation
For iOS7 support, I'd suggest you turn View controller-based status bar appearance back to YES. This will allow you to control the status bars in code. The iOS transition guide (link) provides other options for managing the status bar appearance (there is not just a single fix here but a number of settings that will ensure you get what you want). Also be aware that even if you set the appearance in code you will want to update your storyboards or nib files to match your default appearance (otherwise you may see the status bar flash temporarily depending on where you set the code to update the status bar). I would recommend that you set the code before the view appears.
After setting your plist property to YES: Be sure this method exists in UIViewController where you want to status bar to disappear:
- (BOOL)prefersStatusBarHidden
{
return YES;
}
Showing the Status Bar
Return No if you'd like the status bar to appear in each of your view controllers.
There can be a number of other status bar related issues:
Preventing the Status Bar from Covering Your Views
Views incorrectly draw underneath the status bar
Alternative Approach
According to Apple's Documentation you can use another method of managing the status bar by leveraging the UIApplication method noted in the reference below (link). setStatusBarHidden is still viable when using this approach.
This option will allow you to continue to use the UIApplication class properties if you follow the plist setting above.
Samples
You can find code samples of the status bar alternative option mentioned above in:
AVPlayerDemo
GLPaint
StitchedStreamPlayer
If the view controller that is on screen is the root view controller then you should just be able to implement the function
- (BOOL)prefersStatusBarHidden {
return _showStatusBar;
}
with _showStatusBar being a BOOL, then whenever you change that property call [self setNeedsStatusBarAppearanceUpdate]
If the view controller is being held inside of something else i.e. a UINavigationController then you need to implement the method - (UIViewController *)childViewControllerForStatusBarHidden on the parent controller first and return the currently presented view controller instance.
This is all with View controller-based status bar appearance set to YES
i think this will work under summary page of your app or else reply me
visibility ---check that box

Resources