I'm trying to create this layout programmatically in Swift.
https://codepen.io/anon/pen/NXRQbJ
The first rectangle is small. And the other 2 rectangles are the same size but bigger than the first rectangle.
Here is the entire View Controller. I am not using storyboard. All my code is in this view controller.
import UIKit
class ViewController: UIViewController {
lazy var stackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [smallRectangleView, bigRectangleView, bigRectangleView2])
stackView.alignment = .fill
stackView.distribution = .fillProportionally
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
var smallRectangleView: UIView = {
let view = UIView()
view.backgroundColor = .orange
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var bigRectangleView: UIView = {
let view = UIView()
view.backgroundColor = .green
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var bigRectangleView2: UIView = {
let view = UIView()
view.backgroundColor = .purple
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
setupLayout()
print(stackView.frame)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setupLayout() {
// Stack View
view.addSubview(stackView)
stackView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
// Small Recntangle View
let heightConstraint1 = NSLayoutConstraint(item: smallRectangleView, attribute: .height, relatedBy: .equal, toItem: bigRectangleView, attribute: .height, multiplier: 4.0, constant: 0.0)
// Big Rectangle View
let heightConstraint2 = NSLayoutConstraint(item: bigRectangleView, attribute: .height, relatedBy: .equal, toItem: bigRectangleView2, attribute: .height, multiplier: 0.0, constant: 0.0)
view.addConstraints([heightConstraint1, heightConstraint2])
}
}
// Small Recntangle View
let heightConstraint1 = NSLayoutConstraint(item: smallRectangleView, attribute: .height, relatedBy: .equal, toItem: bigRectangleView, attribute: .height, multiplier: 4.0, constant: 0.0)
// Big Rectangle View
let heightConstraint2 = NSLayoutConstraint(item: bigRectangleView, attribute: .height, relatedBy: .equal, toItem: bigRectangleView2, attribute: .height, multiplier: 0.0, constant: 0.0)
view.addConstraints([heightConstraint1, heightConstraint2])
The main problem seems to be the stackView.distribution
. I changed it from .fillProportionally
to just .fill
. I suspect the issue was that the views were already relative to each other because of your constraints and that lead to conflicts.
Other changes I made, your multiplier
in one of your constraints needs to be 0.25
instead of 4
, and in the second one the multiplier needs to be 1
instead of 0
.
I also used NSLayoutConstraint.activate
to activate the last 2 constraints instead of adding them to the view
. In general, you want to activate constraints instead of adding them to views. Let iOS figure out which views to add them to.
class ViewController: UIViewController {
lazy var stackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [smallRectangleView, bigRectangleView, bigRectangleView2])
stackView.alignment = .fill
stackView.distribution = .fill
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
var smallRectangleView: UIView = {
let view = UIView()
view.backgroundColor = .orange
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var bigRectangleView: UIView = {
let view = UIView()
view.backgroundColor = .green
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var bigRectangleView2: UIView = {
let view = UIView()
view.backgroundColor = .purple
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
setupLayout()
print(stackView.frame)
}
func setupLayout() {
// Stack View
view.addSubview(stackView)
stackView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
// Small Recntangle View
let heightConstraint1 = NSLayoutConstraint(item: smallRectangleView, attribute: .height, relatedBy: .equal, toItem: bigRectangleView, attribute: .height, multiplier: 0.25, constant: 0.0)
// Big Rectangle View
let heightConstraint2 = NSLayoutConstraint(item: bigRectangleView, attribute: .height, relatedBy: .equal, toItem: bigRectangleView2, attribute: .height, multiplier: 1.0, constant: 0.0)
NSLayoutConstraint.activate([heightConstraint1, heightConstraint2])
}
}