3

I have gone around and around on this. I just want to hide the status bar on devices smaller than the iPhone 6. This answer is great but the code is now deprecated and throws an error.

I followed all the advice on this post (which was very helpful), and I have working code, but I have to copy and paste onto every view controller. That seems like a bad idea. It certainly doesn't abide by the DRY method.

Here is my code that works for a single view controller:

class Step1SplashVC: UIViewController {

var hideStatusBar: Bool = false

override var prefersStatusBarHidden: Bool { return true }

override func viewDidLoad() {
    super.viewDidLoad()

    let screenSize = Int(UIScreen.main.bounds.width)

    print("screen size:", screenSize)

    if screenSize <= 320 {
        print("device is too small. need to hide status bar")
        hideStatusBar = true
        setNeedsStatusBarAppearanceUpdate()
    }

My question is, how do I refactor this so that I'm not copying and pasting to every view controller in my project (I have about 35 view controllers in all)?

I tried creating an extension for UIViewController, but it kept throwing an error.

Here is the bad code:

extension UIViewController {

    private struct Holder {
        static var hideStatusBar: Bool = false
    }

    var screensize: Bool {
        get {
            return Int(UIScreen.main.bounds.width) <= 320
        }

        set {
            Holder.hideStatusBar = true
        }
    }

    override var prefersStatusBarHidden: Bool { return true }
}

The error I get is:

Property does not override any property from its superclass

So my efforts at creating an extension are not working.

How can I hide the status bar for smaller devices without having to copy and paste code onto every view controller?

Thanks!!

shim
  • 9,289
  • 12
  • 69
  • 108
Phontaine Judd
  • 428
  • 7
  • 17
  • I don't quite understand from your code though how `hideStatusBar` works if `prefersStatusBarHidden` always returns `true`…? – shim Mar 14 '19 at 15:32
  • @shim It doesn't work. I started coding the computed property and got stuck with the 'override var' part. I didn't finish the computed property code for the 'set' part. – Phontaine Judd Mar 14 '19 at 15:38

4 Answers4

1

Take that code that you wrote (which works for a single view controller) and put it into a BaseViewController, a subclass of UIViewController:

class BaseViewController: UIViewController {

    var hideStatusBar: Bool = false

    override var prefersStatusBarHidden: Bool { return true }

    override func viewDidLoad() {
        super.viewDidLoad()

        let screenSize = Int(UIScreen.main.bounds.width)

        print("screen size:", screenSize)

        if screenSize <= 320 {
            print("device is too small. need to hide status bar")
            hideStatusBar = true
            setNeedsStatusBarAppearanceUpdate()
        }
    }
}

Then you can subclass BaseViewController on each of your view controllers in your project (replacing class XYZViewController: UIViewController), and implement super.viewDidLoad(), for example:

class Step1SplashVC: BaseViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //Whatever you want, specific to each VC
    }
}
10623169
  • 984
  • 1
  • 12
  • 22
  • So I still have to add the subclass in to each VC, but I won't have to copy all the same code into each VC. Just subclass on each VC and I'm good to go, right? – Phontaine Judd Mar 14 '19 at 22:30
  • Exactly - instead of your VCs subclassing `UIViewController` all you're doing is subclassing your custom `BaseViewController`. – 10623169 Mar 15 '19 at 10:24
  • 1
    Thank you for the code. I understand the concept of subclassing now and how to apply it to this particular situation. It makes sense. – Phontaine Judd Mar 16 '19 at 02:08
0

Extensions cannot / should not override properties/methods from the classes they extend; see more on that here.

Alternatively you could subclass UIViewController and implement prefersStatusBarHidden in the subclass, but then you'd have to apply that subclass to all your view controllers.

Note also if your app's flow is centred around UINavigationController for example, you may be able to implement your changes in a single subclass of that rather than in each UIViewController.

An example using UIViewController subclassing (you may want to structure your implementation differently):

class MyViewControllerBaseClass: UIViewController {
    override var prefersStatusBarHidden: Bool {
        return shouldHideStatusBar 
    }

    var shouldHideStatusBar = true
}

// ……… meanwhile in some other file…

class SomeViewController: MyViewControllerBaseClass {
    // this class now inherits the above property and the implementation of prefersStatusBarHidden
}

You can put your code for checking the screen size in the base class as well.

shim
  • 9,289
  • 12
  • 69
  • 108
0

You can simply hide status bar in AppDelegate.swift. Only three steps are needed:

1) In Info.plist add new row.

Key: View controller-based status bar appearance

Value: No

2) Now in AppDelegate.swift add two variables to get width and height , like this:

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    //----- These lines should be added
    public var screenWidth: CGFloat {
        return UIScreen.main.bounds.width
    }
    public var screenHeight: CGFloat {
        return UIScreen.main.bounds.height
    }
    //------ End
}

3) Now you have size of device's screen and you have permission to hide status bar. In AppDelegate.swift you have function like this (default it is on top and your first function in AppDelegate.swift):

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

In this function you just one time check screen size and if it was smaller than 320 (smaller than iPhone SE) then you hide status bar like this:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        //----- These lines should be added
        if(self.screenWidth < 320) {
            UIApplication.shared.isStatusBarHidden = true
        }
        //------ End

        return true
    }

That's it.

In this way you check screen size and hide/show status bar just one time.

Hope to be useful. Also sorry about my English.

Abbas Habibnejad
  • 433
  • 5
  • 14
  • Unfortunately this won't work. There are a couple of problems. 1. By setting the plist key `View controller-based status bar appearance` to NO, I'm no longer able to set display for individual view controllers. 2. `UIApplication.shared.isStatusBarHidden = true` is deprecated in iOS 9. – Phontaine Judd Mar 14 '19 at 22:23
0

var screenHeight: CGFloat = UIScreen.main.bounds.size.height

if screenHeight < 667 {
    UIApplication.shared.isStatusBarHidden = true
}