0

I am building an iOS app, deployment target 12.1, swift 4.2. The app uses container views and has a navigation bar at the top of the main screens, preferably right under the status bar. In the launchscreen storyboard, I have constrained Navigation Bar.top to Safe.Area.Top. That works fine. But after I set the containerViewController to be the rootViewController in the AppDelegate, the navigation bar as I've constrained it in Main.storyboard (Navigation Bar.top to Safe.Area.Top) appears far below where it should be.

The only way I can get the navigation bar to appear right under the status bar is to create a custom frame for my window in AppDelegate with a negative y-value -- and that is definitely NOT a solution I'm comfortable with.

This seems to generate a y-value too low:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        window = UIWindow(frame: UIScreen.main.bounds)
        let containerViewController = ContainerViewController()
        window!.rootViewController = containerViewController
        window!.makeKeyAndVisible()
        return true
    }

And this is the egregious hack that gets the navigation bar closer to where it should be:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        //window = UIWindow(frame: UIScreen.main.bounds)
        let hackedFrame = CGRect(x: 0, y: -44, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
        window = UIWindow(frame: hackedFrame)
        let containerViewController = ContainerViewController()
        window!.rootViewController = containerViewController
        window!.makeKeyAndVisible()
        //window!.windowLevel = UIWindow.Level.statusBar
        return true
    }

Screen grabs:

launchscreen, navbar correct

main screen post didFinishLaunchingWithOptions, navbar too low

I'm probably missing something really obvious here, but I'd appreciate any help anyone can give.

Thanks.

Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • If we are creating "window" and its "rootViewController" by code inside the "app delegate" the main.storyboard will become useless. App will show only those changes which you will make inside the viewcontroller class. – Akash Bhardwaj Apr 13 '19 at 08:33
  • Plz share the code of your "ContainerViewController" class also, it will help us to provide a better answer. – Akash Bhardwaj Apr 13 '19 at 08:34
  • Does the storyboard really become useless? As you see from the screen shots I posted, the navbar and button I build still exist. Button functions perfectly. It's just set ~44 points too low. – user2271541 Apr 15 '19 at 14:34
  • In my experience it does become useless unless & until you specifically invoke the storyboard in your code somewhere. Considering your scenario I think you must have added the "navigation bar" somewhere in your "ContainerViewController" class "code" also. – Akash Bhardwaj Apr 15 '19 at 18:13
  • I see what you're saying. I actually figured out the root cause of the problem. I'm basing my project on someone else's pre-existing code (always dangerous). They were targeting an earlier os version and using layout guides, which are deprecated now. Long story short, I'm handling the UI mostly programmatically, and having no problems. Thanks for your help, anyway! – user2271541 Apr 15 '19 at 21:49

2 Answers2

0

In iOS 11 Apple introduced large titles in the navigation bar, which means that it can be stretched if pulled. You should try setting

navigationItem.largeTitleDisplayMode = .never

In your viewDidLoad, and set the prefersLargeTitles of your navigation bar to false

if #available(iOS 11.0, *) {
   navigationItem.largeTitleDisplayMode = .always
   navigationController?.navigationBar.prefersLargeTitles = true
} 
0

try adding the navigation bar in ViewController instead of AppDelegate like this:

var screenWidth : CGFloat!
var screenHeight : CGFloat!
let screenSize: CGRect = UIScreen.main.bounds

inside ViewDidLoad:

screenWidth = screenSize.width
screenHeight = screenSize.height

navigationBar = UINavigationBar(frame: CGRect(x: 0, y: 20, width: screenWidth, height: screenWidth / 3))

for adding title and button:

view.addSubview(navigationBar)
    let navItem = UINavigationItem(title: "MainController")
    let doneItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.cancel, target: nil, action: #selector(DismissViewController))
    navItem.leftBarButtonItem = doneItem
    UINavigationBar.appearance().barTintColor = .white
    navigationBar.setItems([navItem], animated: false)
Arash Afsharpour
  • 1,282
  • 11
  • 22
  • Yep, this seems to have done the trick. I'm new-ish to iOS and xcode, I'll admit, but man, I have terrible luck with the interface builder. Programmatic solutions to ui issues generally work best for me. Thanks. – user2271541 Apr 12 '19 at 22:10
  • I do the same since last week, I do all the UI in code now, I delete Storyboard right when I start a new project, I recommend you use Snapkit library for managing UI it makes it really easier for you – Arash Afsharpour Apr 13 '19 at 06:08