I want to show the status bar on portrait mode only, when I rotate the screen the status bar hides as intended but if I push / show a new View Controller the status bar appears again.
I've tried the following without success:
Setting View controller-based status bar appearance to NO in the info.plist file
Using setNeedsStatusBarAppearanceUpdate() on self and on NavigationController
Setting prefersStatusBarHidden: Bool to true
Also tried UIApplication.shared.setStatusBarHidden(true, with: UIStatusBarAnimation.none)
Also extending NavigationController. seen here
Any help will be appreciated. Thanks.
Try Following Code
override var prefersStatusBarHidden: Bool {
if UIDevice.current.orientation.isPortrait{
return false
}
return true
}
I am making one custom keyboard in which when orientation of mobile is changed then in landscape i have to hide one button please suggest how can i do this i am using below code to do this task please help me.
in landscape also the button is visible i want to hide button on landscape and visible in portrait mode
override func updateViewConstraints() {
super.updateViewConstraints()
// Add custom view sizing constraints here
var currentDevice: UIDevice = UIDevice.currentDevice()
var orientation: UIDeviceOrientation = currentDevice.orientation
if orientation.isLandscape {
button.hidden = true
}
if orientation.isPortrait {
button.hidden = false
}
}
In your viewDidLoad put
NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationChanged", name: UIDeviceOrientationDidChangeNotification, object: nil)
Then add this method
func orientationChanged()
{
if(UIDeviceOrientationIsLandscape(UIDevice.currentDevice().orientation))
{
button.hidden = true
}
if(UIDeviceOrientationIsPortrait(UIDevice.currentDevice().orientation))
{
button.hidden = false
}
}
Note:
UIDevice.currentDevice().orientation might not give you the correct orientation. You can use the status bar orientation instead UIApplication.sharedApplication().statusBarOrientation
From the apple docs:
UIDevice.currentDevice().orientation
The value of the property is a constant that indicates the current
orientation of the device. This value represents the physical
orientation of the device and may be different from the current
orientation of your application’s user interface. See
“UIDeviceOrientation” for descriptions of the possible values.
How can I had the status bar whenever the view is scrolling with:
self.navigationController?.hidesBarsOnSwipe = true
or if not hide the status bar, how can I keep my status bar from overlaying my view?
ty awesome stackoverflow community
A Swift 3 elegant solution:
open override var prefersStatusBarHidden: Bool {
return navigationController?.isNavigationBarHidden ?? false
}
Sorry if this answer is a little late, but here is one way to do it.
Use the prefersStatusBarHidden() method within your view controller.
override func prefersStatusBarHidden() -> Bool {
if self.navigationController?.navigationBarHidden == true {
return true
} else {
return false
}
}
Basically says that when the Nav bar is hidden, then the status bar is too and vice versa.
I've try to modify status bar color text but no one answer from this thread doesn't work.
Any especially for XCode 6?
I've tried insert:
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent
}
to UIViewController
also
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true)
to AppDelegate.swift
And I've tried change it in info.plist
But it doesn't affect it. How change status bar color text to white?
In your Info.plist you need to define View controller-based status bar appearance to any value.
If you define it YES then you should override preferredStatusBarStyle function in each view controller.
If you define it NO then you can set style in AppDelegate using
UIApplication.sharedApplication().statusBarStyle = .LightContent
Just set " View controller-based status bar appearance == NO " in to your plist and put a single line in your appdelegate class in didfinshLaunching method.
UIApplication.sharedApplication().statusBarStyle = .LightContent
Swift 3.0
Just set View controller-based status bar appearance == NO in to your *.plist and put below code in your appdelegate class in didFinishLaunchingWithOptions method before return.
let statusBar: UIView = UIApplication.shared.value(forKey: "statusBar") as! UIView
if statusBar.responds(to:#selector(setter: UIView.backgroundColor)) {
statusBar.backgroundColor = UIColor.red
}
UIApplication.shared.statusBarStyle = .lightContent
You can change backgroundColor and statusBarStyle as per your requirement.
Be sure to set the View controller-based status bar appearance in your info.plist file to Yes.
Furthermore, if you are in a UINavigationController, you cannot simply set the style in ViewControllers in it. Subclass the UINavigationController and add this to it:
override func preferredStatusBarStyle() -> UIStatusBarStyle {
if let vc = self.viewControllers?.last as? UIViewController {
return vc.preferredStatusBarStyle()
}
return super.preferredStatusBarStyle()
}
Now you can set the bar style in the UIViewController subclass and the UINavigationController will listen to it :).
Keenle is right on, from iOS7 onward, you have to opt out of viewController-based status bar styles before you can set it app-wide.
doc:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html#//apple_ref/occ/instm/UIApplication/setStatusBarStyle:animated:
"To opt out of the view controller-based status bar appearance behavior, you must add the UIViewControllerBasedStatusBarAppearance key with a value of NO to your app’s Info.plist file, but doing so is not recommended."
In my iPhone application built with Xcode 5 for iOS 7 I set UIViewControllerBasedStatusBarAppearance=YES in info.plist, and in my ViewController I have this code:
-(UIStatusBarStyle) preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
But the status bar is still black against the black background.
I know its possible to change this app-wide by setting UIViewControllerBasedStatusBarAppearance=NO in info.plist, but I actually need to alter this on a viewController by viewController basis at runtime.
I discovered that if your ViewController is inside a navigationController then the navigationController’s navigationBar.barStyle determines the statusBarStyle.
Setting your navigationBar’s barStyle to UIBarStyleBlackTranslucent will give white status bar text (ie. UIStatusBarStyleLightContent), and UIBarStyleDefault will give black status bar text (ie. UIStatusBarStyleDefault).
Note that this applies even if you totally change the navigationBar’s color via its barTintColor.
OK, here's the trick. You do have to add the key "View controller-based status bar" and set the value to No.
This is counter to what it appears the meaning of this key is, but even if you set the value to No, you can still change the appearance of the status bar, and whether it shows or not in any view controller. So it acts like "Yes" but set it to "No"!
Now I can get the status bar white or dark.
For preferredStatusBarStyle() to work within UINavigationController and UITabBarController I add the following code, which will get the preferred status bar style from the currently visible view controller.
extension UITabBarController {
public override func childViewControllerForStatusBarStyle() -> UIViewController? {
return selectedViewController
}
}
extension UINavigationController {
public override func childViewControllerForStatusBarStyle() -> UIViewController? {
return visibleViewController
}
}
For Swift 3 those are not methods but properties:
extension UITabBarController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return selectedViewController
}
}
extension UINavigationController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return visibleViewController
}
}
The Swift 4.2 properties have been renamed:
extension UITabBarController {
open override var childForStatusBarStyle: UIViewController? {
return selectedViewController
}
}
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
return visibleViewController
}
}
Usage
class ViewController: UIViewController {
// This will be called every time the ViewController appears
// Works great for pushing & popping
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
I may be coming to this a bit late, but incase anyone else is looking for a working and verified app wide solution.
#mxcl is correct in describing why this is happening. In order to correct it, we simply create an extension (or category in obj-c) that overrides the preferredSatusBarStyle() method of UINavigationController. Here is an example in Swift:
extension UINavigationController {
public override func preferredStatusBarStyle() -> UIStatusBarStyle {
if let rootViewController = self.viewControllers.first {
return rootViewController.preferredStatusBarStyle()
}
return super.preferredStatusBarStyle()
}
}
This code simply extracts the first view controller (the root view controller) and unwraps it (in obj-c just check that it is not nil). If the unwrap is successful (not nil) then we grab the rootViewControllers preferredStatusBarStyle. Otherwise we just return the default.
Hope this helps anyone who might need it.
To provide more detail into the accepted answer, put the following line in your app delegate's didFinishLaunchingWithOptions: method:
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
Then, in your Info.plist, add View controller-based status bar appearance and set it to NO.
I believe that's how it should be done, NOT from the navigation controller, if you want the same status bar color for the entire app. You might have screens that are not necessarily embedded in a UINavigationController, or a different UINavigationController subclass somewhere else, and other things.
EDIT: You can also do it without typing any code: https://stackoverflow.com/a/18732865/855680
In viewDidLoad just write this
[self setNeedsStatusBarAppearanceUpdate];
just do that and it will work
can u please try this
Set UIViewControllerBasedStatusBarAppearance to NO.
Call [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
One more thing i have seen in your question that
you have wrote the method like this
-(void)UIStatusBarStyle PreferredStatusBarStyle ()
{
return UIStatusBarStyle.LightContent;
}
but it should be like this
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
iOS 13 Solution(s)
The highest-voted answer uses "legacy" code 👎
Setting the barStyle property is now (iOS 13+) considered a "legacy customization." According to Apple,
In iOS 13 and later, customize your navigation bar using the standardAppearance, compactAppearance, and scrollEdgeAppearance properties. You may continue to use these legacy accessors to customize your navigation bar's appearance directly, but you must update the appearance for different bar configurations yourself.
Regarding your attempt - You were on the right track!
UINavigationController is a subclass of UIViewController (who knew 🙃)!
Therefore, when presenting view controllers embedded in navigation controllers, you're not really presenting the embedded view controllers; you're presenting the navigation controllers! UINavigationController, as a subclass of UIViewController, inherits preferredStatusBarStyle and childForStatusBarStyle, which you can set as desired.
Any of the following methods should work:
Override preferredStatusBarStyle within UINavigationController
preferredStatusBarStyle (doc) - The preferred status bar style for the view controller
Subclass or extend UINavigationController
class MyNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}
OR
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}
Override childForStatusBarStyle within UINavigationController
childForStatusBarStyle (doc) - Called when the system needs the view controller to use for determining status bar style
According to Apple's documentation,
"If your container view controller derives its status bar style from one of its child view controllers, [override this property] and return that child view controller. If you return nil or do not override this method, the status bar style for self is used. If the return value from this method changes, call the setNeedsStatusBarAppearanceUpdate() method."
In other words, if you don't implement solution 3 here, the system will fall back to solution 2 above.
Subclass or extend UINavigationController
class MyNavigationController: UINavigationController {
override var childForStatusBarStyle: UIViewController? {
topViewController
}
}
OR
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
topViewController
}
}
You can return any view controller you'd like above. I recommend one of the following:
topViewController (of UINavigationController) (doc) - The view controller at the top of the navigation stack
visibleViewController (of UINavigationController) (doc) - The view controller associated with the currently visible view in the navigation interface (hint: this can include "a view controller that was presented modally on top of the navigation controller itself")
Note: If you decide to subclass UINavigationController, remember to apply that class to your nav controllers through the identity inspector in IB.
P.S. My code uses Swift 5.1 syntax 😎
Here is how I solved it. Usually the navigationController or tabBarController are the ones deciding the appearance of the status bar (hidden, color, etc).
So I ended up subclassing the navigation controller and overriding preferredStatusBarStyle. if the current visible ViewContorller implements StatusBarStyleHandler I ask for the value to be used as the style, if it doesn't I just return a default value.
The way you trigger an update of the status bar appearance is by calling setNeedsStatusBarAppearanceUpdate which triggers preferredStatusBarStyle again and updates UI according to what the method returns
public protocol StatusBarStyleHandler {
var preferredStatusBarStyle: UIStatusBarStyle { get }
}
public class CustomNavigationCotnroller: UINavigationController {
public override var preferredStatusBarStyle: UIStatusBarStyle {
if let statusBarHandler = visibleViewController as? StatusBarStyleHandler {
return statusBarHandler.preferredStatusBarStyle
}
return .default
}
}
Then usage
public class SomeController: UIViewController, StatusBarStyleHandler {
private var statusBarToggle = true
// just a sample for toggling the status bar style each time method is called
private func toggleStatusBarColor() {
statusBarToggle = !statusBarToggle
setNeedsStatusBarAppearanceUpdate()
}
public override var preferredStatusBarStyle: UIStatusBarStyle {
return statusBarToggle ? .lightContent : .default
}
}
Even with all the answers here i still didn't find the exact solution for me, but started with the answer from Daniel. What I ended up with was:
override var preferredStatusBarStyle: UIStatusBarStyle {
return visibleViewController?.preferredStatusBarStyle ?? .lightContent
}
in navigation controllers (similar for tab, just selectedViewController). And then it will respect the:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
In each view controller unless you set it otherwise. I dont need to call setNeedsStatusBarAppearanceUpdate() anywhere, it just updates when you arrive at each view controller.
1) One setting for whole project:
If available, remove UIViewControllerBasedStatusBarAppearance key-value pair from your info.plist, or set NO without removing it. If it's not available in your info.plist, do nothing. Default is NO for this property.
Add below code to your AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}
2) Different settings for different View Controllers:
Add UIViewControllerBasedStatusBarAppearance key-value pair to your info.plist and set it to YES.
If your View Controller is not embed in to Navigation Controller. Let's say MyViewController. just add code below to your MyViewController.m file. If your View Controller is embed in to Navigation Controller, create a new Cocoa Touch Class and make it subclass of UINavigationController. Let's say MyNC. Select Navigation Controller View on your Storyboard, at right pane; Utilities -> Identity Inspector -> Custom Class -> Class, type "MyNC". After linking Storyboard View with your "MyNC" Cocoa Touch Class, add code below to your MyNC.m:
- (BOOL)prefersStatusBarHidden {
return NO;
}
-(UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
If in case you wanted to hide the statusBar during splashScreen but wanted to change the style to light content (StatusBarInitiallyHidden on Plist has to be NO to hide statusBar on splash), you can add this to appDelegate's didFinishLaunchingWithOptions method to change to lightContent.
[[UIApplication sharedApplication]setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent];
swift example
in AppDelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent;
return true
}
in info.plist set View controller-based status bar appearance: NO
If you're using NavigationController, you can subclass NavigationController so that it consults its child view controller
// MyCustomNavigationController
- (NSUInteger)supportedInterfaceOrientations {
UIViewController *viewControllerToAsk = [self findChildVC];
return [viewControllerToAsk supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotate {
UIViewController *viewControllerToAsk = [self findChildVC];
return [viewControllerToAsk shouldAutorotate];
}
- (UIStatusBarStyle)preferredStatusBarStyle {
UIViewController *viewControllerToAsk = [self findChildVC];
return [viewControllerToAsk preferredStatusBarStyle];
}
- (UIViewController *)findChildVC {
return self.viewControllers.firstObject;
}
Swift 4.2
extension UITabBarController {
open override var childForStatusBarStyle: UIViewController? {
return selectedViewController
}
}
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
return visibleViewController
}
}
You can set the status bar style. It will resembles the status bar like IOS 6 and below.
Paste this methods in your view controller
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleBlackOpaque;
}
and call this method from view did load like this
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f)
{
[self setNeedsStatusBarAppearanceUpdate];
}
swift example
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent;
return true
}
in info.plist set View controller-based status bar appearance: NO
I just want to add a note for a specific case I faced. I had another UIWindow in my app to display a chat face to be floating all over my app all the time. Doing this caused none of the solution above to work, and I am not really sure why! All what I have noticed is that my ViewController in the new UIWindow was the reason for that! And if I wanted to change the status bar style I have to do it in that view controller of the new UIWindow.
This note might help others who have a similar structure! So basically you can apply the solutions mentioned above in the ViewController of the new UIWindow.
Again this a specific case.
Thanks
Wanna some tricky? No needs to override status bar style in every view controller
First: Follow #Sahil Kapoor, add 'View controller-based status bar = YES' to plist
Second: Make a subclass of window's root view controller and return StatusBarTrackingController.
final class StatusBarTracker: UIViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
CustomThemeProvider.currentTheme.asStatusBarStyle
}
}
final class TabBarController: UITabBarController {
private let statusBarTracker = StatusBarTracker()
override var childForStatusBarStyle: UIViewController? {
statusBarTracker
}
}
extension TabBarController: CustomThemeUpdatable {
func applyCustomTheme(_ theme: CustomTheme) {
setNeedsStatusBarAppearanceUpdate()
}
}
// SceneDelegate
window?.rootViewController = TabBarController()
For swift 3, in your UIViewController:
override var preferredStatusBarStyle : UIStatusBarStyle { return UIStatusBarStyle.lightContent }