Reputation: 3011
Update:
Thanks everyone for the unique approaches. Appreciate your insights.
Background:
I have written some code below in Xcode Swift 5 that creates four equal sized rectangles that resize depending on the device size and orientation.
However, the desired result is a rectangle with different heights, where the top rectangles are variable heights depending on the device size and orientation, and the bottom rectangles are with a constant height of 200px.
Question:
What changes to my code do I need to make to achieve variable heights on top and fixed heights on bottom?
Code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let frameTopLeft = UIView()
frameTopLeft.backgroundColor = .systemRed
view.addSubview(frameTopLeft)
frameTopLeft.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameTopLeft.topAnchor.constraint(equalTo: view.topAnchor),
frameTopLeft.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5),
frameTopLeft.leftAnchor.constraint(equalTo: view.leftAnchor),
frameTopLeft.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5)
])
let frameTopRight = UIView()
frameTopRight.backgroundColor = .systemBlue
view.addSubview(frameTopRight)
frameTopRight.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameTopRight.topAnchor.constraint(equalTo: view.topAnchor),
frameTopRight.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5),
frameTopRight.rightAnchor.constraint(equalTo: view.rightAnchor),
frameTopRight.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5)
])
let frameBottomLeft = UIView()
frameBottomLeft.backgroundColor = .systemGreen
view.addSubview(frameBottomLeft)
frameBottomLeft.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameBottomLeft.bottomAnchor.constraint(equalTo: view.bottomAnchor),
frameBottomLeft.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5),
frameBottomLeft.leftAnchor.constraint(equalTo: view.leftAnchor),
frameBottomLeft.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5)
])
let frameBottomRight = UIView()
frameBottomRight.backgroundColor = .systemYellow
view.addSubview(frameBottomRight)
frameBottomRight.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameBottomRight.bottomAnchor.constraint(equalTo: view.bottomAnchor),
frameBottomRight.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5),
frameBottomRight.rightAnchor.constraint(equalTo: view.rightAnchor),
frameBottomRight.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5)
])
}
}
Images:
Simulator output.
Desired output.
Upvotes: 0
Views: 619
Reputation: 87804
I'd do it like this:
let frameTopLeft = UIView()
frameTopLeft.backgroundColor = .systemRed
view.addSubview(frameTopLeft)
frameTopLeft.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameTopLeft.topAnchor.constraint(equalTo: view.topAnchor),
frameTopLeft.leftAnchor.constraint(equalTo: view.leftAnchor),
])
let frameTopRight = UIView()
frameTopRight.backgroundColor = .systemBlue
view.addSubview(frameTopRight)
frameTopRight.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameTopRight.topAnchor.constraint(equalTo: view.topAnchor),
frameTopRight.rightAnchor.constraint(equalTo: view.rightAnchor),
frameTopRight.leftAnchor.constraint(equalTo: frameTopLeft.rightAnchor),
frameTopRight.widthAnchor.constraint(equalTo: frameTopLeft.widthAnchor)
])
let frameBottomLeft = UIView()
frameBottomLeft.backgroundColor = .systemGreen
view.addSubview(frameBottomLeft)
frameBottomLeft.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameBottomLeft.topAnchor.constraint(equalTo: frameTopLeft.bottomAnchor),
frameBottomLeft.bottomAnchor.constraint(equalTo: view.bottomAnchor),
frameBottomLeft.leftAnchor.constraint(equalTo: view.leftAnchor),
frameBottomLeft.heightAnchor.constraint(equalToConstant: 200),
])
let frameBottomRight = UIView()
frameBottomRight.backgroundColor = .systemYellow
view.addSubview(frameBottomRight)
frameBottomRight.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameBottomRight.topAnchor.constraint(equalTo: frameTopRight.bottomAnchor),
frameBottomRight.bottomAnchor.constraint(equalTo: view.bottomAnchor),
frameBottomRight.rightAnchor.constraint(equalTo: view.rightAnchor),
frameBottomRight.leftAnchor.constraint(equalTo: frameBottomLeft.rightAnchor),
frameBottomRight.heightAnchor.constraint(equalTo: frameBottomLeft.heightAnchor),
frameBottomRight.widthAnchor.constraint(equalTo: frameBottomLeft.widthAnchor),
])
The main diff from others is getting rid of constants as much as possible.
It makes you code easier to maintain, decreasing places to edit.
Upvotes: 1
Reputation: 77462
You want to give the Bottom views constant Height constraints of 200, and then constrain the Bottoms of the top views to the Tops of the Bottom views.
You may find it helpful to group related code together, and add comments as you go (to make it a little clearer what you believe the code should do).
So, try it like this:
override func viewDidLoad() {
super.viewDidLoad()
// create 4 views
let frameTopLeft = UIView()
let frameTopRight = UIView()
let frameBottomLeft = UIView()
let frameBottomRight = UIView()
// set background colors
frameTopLeft.backgroundColor = .systemRed
frameTopRight.backgroundColor = .systemBlue
frameBottomLeft.backgroundColor = .systemGreen
frameBottomRight.backgroundColor = .systemYellow
// set Autoresizing and add to view
[frameTopLeft, frameTopRight, frameBottomLeft, frameBottomRight].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
}
NSLayoutConstraint.activate([
// top-left view constrained Top / Left / 50% Width
frameTopLeft.topAnchor.constraint(equalTo: view.topAnchor),
frameTopLeft.leftAnchor.constraint(equalTo: view.leftAnchor),
frameTopLeft.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5),
// top-right view constrained Top / Right / 50% Width
frameTopRight.topAnchor.constraint(equalTo: view.topAnchor),
frameTopRight.rightAnchor.constraint(equalTo: view.rightAnchor),
frameTopRight.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5),
// bottom-left view constrained Bottom / Left / 50% Width
frameBottomLeft.bottomAnchor.constraint(equalTo: view.bottomAnchor),
frameBottomLeft.leftAnchor.constraint(equalTo: view.leftAnchor),
frameBottomLeft.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5),
// bottom-right view constrained Bottom / Right / 50% Width
frameBottomRight.bottomAnchor.constraint(equalTo: view.bottomAnchor),
frameBottomRight.rightAnchor.constraint(equalTo: view.rightAnchor),
frameBottomRight.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5),
// bottom views, constant Height of 200-pts
frameBottomLeft.heightAnchor.constraint(equalToConstant: 200.0),
frameBottomRight.heightAnchor.constraint(equalToConstant: 200.0),
// constrain bottoms of top views to tops of bottom views
frameTopLeft.bottomAnchor.constraint(equalTo: frameBottomLeft.topAnchor),
frameTopRight.bottomAnchor.constraint(equalTo: frameBottomRight.topAnchor),
])
}
Upvotes: 1
Reputation: 18914
Use StackView for better code and understanding.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let topStack = UIStackView()
topStack.axis = .horizontal
topStack.distribution = .fillEqually
let frameTopLeft = UIView()
frameTopLeft.backgroundColor = .systemRed
topStack.addArrangedSubview(frameTopLeft)
let frameTopRight = UIView()
frameTopRight.backgroundColor = .systemBlue
topStack.addArrangedSubview(frameTopRight)
let bottomStack = UIStackView()
bottomStack.axis = .horizontal
bottomStack.distribution = .fillEqually
let frameBottomLeft = UIView()
frameBottomLeft.backgroundColor = .systemGreen
bottomStack.addArrangedSubview(frameBottomLeft)
let frameBottomRight = UIView()
frameBottomRight.backgroundColor = .systemYellow
bottomStack.addArrangedSubview(frameBottomRight)
frameBottomRight.translatesAutoresizingMaskIntoConstraints = false
frameBottomRight.heightAnchor.constraint(equalToConstant: 200).isActive = true
let mainStack = UIStackView()
mainStack.axis = .vertical
mainStack.addArrangedSubview(topStack)
mainStack.addArrangedSubview(bottomStack)
self.view.addSubview(mainStack)
mainStack.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
mainStack.topAnchor.constraint(equalTo: view.topAnchor),
mainStack.heightAnchor.constraint(equalTo: view.heightAnchor),
mainStack.leftAnchor.constraint(equalTo: view.leftAnchor),
mainStack.widthAnchor.constraint(equalTo: view.widthAnchor)
])
}
}
Or you can give relative constraints to each bottom view.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let frameTopLeft = UIView()
frameTopLeft.backgroundColor = .systemRed
view.addSubview(frameTopLeft)
frameTopLeft.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameTopLeft.topAnchor.constraint(equalTo: view.topAnchor),
// frameTopLeft.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5), << Here
frameTopLeft.leftAnchor.constraint(equalTo: view.leftAnchor),
frameTopLeft.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5)
])
let frameTopRight = UIView()
frameTopRight.backgroundColor = .systemBlue
view.addSubview(frameTopRight)
frameTopRight.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameTopRight.topAnchor.constraint(equalTo: view.topAnchor),
// frameTopRight.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5), << Here
frameTopRight.rightAnchor.constraint(equalTo: view.rightAnchor),
frameTopRight.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5)
])
let frameBottomLeft = UIView()
frameBottomLeft.backgroundColor = .systemGreen
view.addSubview(frameBottomLeft)
frameBottomLeft.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameBottomLeft.topAnchor.constraint(equalTo: frameTopLeft.bottomAnchor), // << Here
frameBottomLeft.bottomAnchor.constraint(equalTo: view.bottomAnchor),
frameBottomLeft.heightAnchor.constraint(equalToConstant: 200), // << Here
frameBottomLeft.leftAnchor.constraint(equalTo: view.leftAnchor),
frameBottomLeft.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5)
])
let frameBottomRight = UIView()
frameBottomRight.backgroundColor = .systemYellow
view.addSubview(frameBottomRight)
frameBottomRight.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
frameBottomRight.topAnchor.constraint(equalTo: frameTopRight.bottomAnchor), // << Here
frameBottomRight.bottomAnchor.constraint(equalTo: view.bottomAnchor),
frameBottomRight.heightAnchor.constraint(equalToConstant: 200), // << Here
frameBottomRight.rightAnchor.constraint(equalTo: view.rightAnchor),
frameBottomRight.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5)
])
}
}
Upvotes: 1