Search code examples
swiftautolayoutequalsnslayoutconstraint

use auto layout to space objects evenly apart


My code below is trying to be based of the photo below. PicLocate should take up 60 percent height of the view. Pic[0] and Pic1 should take up 10 percent height and should be have even width.All of the objects should be spaced of 10 - 15 gap between the views. Mainly it should look just like the photo

enter image description here

    import UIKit
class ViewController: UIViewController {
var picLocate = UIImageView()
var jessicaAlba:Float = 50
var topConstraint: NSLayoutConstraint!
var heightConstraint: NSLayoutConstraint!
var leadingConstraint: NSLayoutConstraint!
var trailingConstraint: NSLayoutConstraint!

let pic = (0..<3).map { _ in UIButton() }


override func viewDidLoad() {
    super.viewDidLoad()

    [picLocate,pic[0],pic[1]].forEach {
        $0.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview($0)
        $0.backgroundColor = .systemOrange
    }


    pic[0].topAnchor.constraint(equalTo: picLocate.bottomAnchor, constant: 10).isActive = true
    pic[0].leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
    pic[0].trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -300).isActive = true
    pic[0].bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -300).isActive = true

    pic[1].topAnchor.constraint(equalTo: picLocate.bottomAnchor, constant: 10).isActive = true
    pic[1].leadingAnchor.constraint(equalTo: pic[0].trailingAnchor, constant: 10).isActive = true
    pic[1].trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
    pic[1].bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -300).isActive = true



    pic[0].setTitle("Add Box", for: .normal)
    pic[1].setTitle("Save Photo", for: .normal)




    topConstraint = picLocate.topAnchor.constraint(equalTo: view.topAnchor, constant: CGFloat(jessicaAlba))
    topConstraint.isActive = true
    heightConstraint = picLocate.heightAnchor.constraint(equalTo: view.heightAnchor , multiplier: 0.6, constant: CGFloat(-jessicaAlba))
    heightConstraint.isActive = true

    leadingConstraint = picLocate.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: CGFloat(jessicaAlba))
    leadingConstraint.isActive = true
    trailingConstraint = picLocate.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: CGFloat(-jessicaAlba))
    trailingConstraint.isActive = true


}

}

Solution

  • It can be very helpful to comment your constraints as you write them. Quite often, that makes you realize what you want to do...

    To get your desired layout, you want to:

    • set picLocate height to 60% of the view height (with your current code, you are also subtracting 50-pts from that 60%)
    • set leading of the left pic (button) to leading of picLocate
    • set trailing of the right pic (button) to trailing of picLocate
    • set leading of right pic to trailing of left pic + 10-pts for spacing
    • then set right pic width equal to left pic width

    Result:

    enter image description here

    and, in landscape orientation, it auto-adjusts to the desired percentages:

    enter image description here

    This is your code, with the changes I described. Take a look, and review the comments:

    class ViewController: UIViewController {
    
        var picLocate = UIImageView()
    
        var jessicaAlba:CGFloat = 50
    
        var topConstraint: NSLayoutConstraint!
        var heightConstraint: NSLayoutConstraint!
        var leadingConstraint: NSLayoutConstraint!
        var trailingConstraint: NSLayoutConstraint!
    
        let pic = (0..<3).map { _ in UIButton() }
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            view.backgroundColor = .white
    
            [picLocate,pic[0],pic[1]].forEach {
                $0.translatesAutoresizingMaskIntoConstraints = false
                view.addSubview($0)
                $0.backgroundColor = .systemOrange
            }
    
            // 50-pts (jessicaAlba) from top of view
            topConstraint = picLocate.topAnchor.constraint(equalTo: view.topAnchor, constant: jessicaAlba)
    
            // 60% of view height minus 50-pts == ((0.6 * view height) - 50)
            heightConstraint = picLocate.heightAnchor.constraint(equalTo: view.heightAnchor , multiplier: 0.6, constant: -jessicaAlba)
    
            // if you actually want 60% of view height, set constant to 0.0
            //heightConstraint = picLocate.heightAnchor.constraint(equalTo: view.heightAnchor , multiplier: 0.6, constant: 0.0)
    
            // 50-pts leading and trailing
            leadingConstraint = picLocate.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: jessicaAlba)
            trailingConstraint = picLocate.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -jessicaAlba)
    
            NSLayoutConstraint.activate([
    
                topConstraint,
                heightConstraint,
                leadingConstraint,
                trailingConstraint,
    
                // "left pic" top is 10-pts below "picLocate" bottom
                pic[0].topAnchor.constraint(equalTo: picLocate.bottomAnchor, constant: 10.0),
    
                // "left pic" leading equal to "picLocate" leading
                pic[0].leadingAnchor.constraint(equalTo: picLocate.leadingAnchor, constant: 0.0),
    
                // "left pic" height equal to 10% of view height
                pic[0].heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.10),
    
                // "right pic" top equal to "left pic" top
                pic[1].topAnchor.constraint(equalTo: pic[0].topAnchor),
    
                // "right pic" height equal to "left pic" height
                pic[1].heightAnchor.constraint(equalTo: pic[0].heightAnchor),
    
                // "right pic" trailing equal to "picLocate" trailing
                pic[1].trailingAnchor.constraint(equalTo: picLocate.trailingAnchor, constant: 0.0),
    
                // "right pic" leading equal to "left pic" trailing plust 10-pts
                pic[1].leadingAnchor.constraint(equalTo: pic[0].trailingAnchor, constant: 10.0),
    
                // "right pic" width equal to "left pic" width
                pic[1].widthAnchor.constraint(equalTo: pic[0].widthAnchor),
    
            ])
    
            pic[0].setTitle("Add Box", for: .normal)
            pic[1].setTitle("Save Photo", for: .normal)
    
        }
    }