Isuru Isuru - 2 months ago 16
iOS Question

Controls positioning under the navigation bar issue

I have a question on Auto layout. I'm using xib files and I have a view controller like this.

enter image description here

Its embedded inside a

UINavigationController
so I have the button positioned with a Top Space to Superview constraint.

The problem is when I rotate the device, it looks like this.

enter image description here

As you can see that constraint still keeps its original value so there's a big gap between the navigation bar edge and the button in landscape mode.

How can I make the button position close to the navigation bar like when its in the portrait and have it that way in both portrait and landscape modes? I'm using Xcode 6 by the way.

Thank you.

Answer

If you want to define your auto layout top margin constraints in your Xib file, you can add the following code in the ViewController's class file relative to your Xib:

override func viewDidLoad() {
    super.viewDidLoad()

    if self.respondsToSelector("edgesForExtendedLayout") {
        edgesForExtendedLayout = UIRectEdge.None
    }
}

Simple. But the problem there is that you won't be able to have a translucent navigation bar.

Fortunately, there are several alternatives to this. You can define your auto layout top margin as relative to your Top Layout Guide (not to your view) with Storyboard or with code.

If you move to Storyboard, click on the Pin button, select your top margin constraint and choose The Top Layout Guide (see image below).

enter image description here

If you decide to define all your UIButton's constraints with code, you can use Visual Format Language as indicated in the following code:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var button = UIButton()
        button.backgroundColor = UIColor.blueColor()

        button.setTranslatesAutoresizingMaskIntoConstraints(false)
        view.addSubview(button)

        var viewsDict = ["button" : button, "topLayoutGuide" : topLayoutGuide]

        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[topLayoutGuide]-20-[button]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-20-[button]-20-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
    }

}

Finally, there is a fourth (kind of mixed) way to perform what you want to do. Set your constraints in your Xib, drag your top margin constraint and your UIButton to your view controller class (name them topConstraint and button) and set your code as the following:

import UIKit

class ViewControllerTwo: UIViewController {

    @IBOutlet weak var topConstraint: NSLayoutConstraint!
    @IBOutlet weak var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addConstraint(NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.topLayoutGuide, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 10))
        view.removeConstraint(topConstraint)
    }

}
Comments