Search code examples
iosswiftlayoutuinavigationcontrolleruinavigationbar

Current View underlapping UINavigationController's navigation bar


I am designing a registration page view, programmatically, for my app where the user can enter in an image of themselves and some info.

In my LoginController I create a UINavigationController with a rootviewcontroller of my RegisterController which is then displayed.

func handleRegisterButtonClicked() {
    let registerController = RegisterController()
    let navController = UINavigationController(rootViewController: registerController)
    present(navController, animated: true, completion: nil)
}

Right now I have added a picture for them to click to upload their photo. I want this picture to always show up 30px underneath the navigation bar, but instead underlaps the navigation bar, showing up 30px from the top of the screen:

Portrait Orientated Landscape Orientated

class RegisterController: UIViewController {
...
func setupViews() {
    profilePic.topAnchor.constraint(equalTo: view.topAnchor, constant: 30).isActive = true
}

Is there a way to add a constraint to the profilePic so that it is anchored to the bottom of the navigation bar (in both portrait and landscape orientations)?


Solution

  • Instead of view.topAnchor try topLayoutGuide.bottomAnchor. This should pin it to the bottom of the navigation bar (the view controller’s “top layout guide”).

    func setupViews() {
        profilePic.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 30).isActive = true
    }
    

    iOS 11 or later

    In iOS 11 topLayoutGuide and bottomLayoutGuide are deprecated in favor of safeAreaLayoutGuide (which is a UIView property, not UIViewController).

    If your app will support iOS 11 you should do the following:

    func setupViews() {
        if #available(iOS 11.0, *) {
            profilePic.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 30).isActive = true
        } else {
            profilePic.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 30).isActive = true
        }
    }
    

    If/when your app only supports iOS 11 or later you can remove the conditional availability check and just go with the safeAreaLayoutGuide version.