StackView with two labels doesn't wrap content - swift

I have one StackView with two labels inside. I want to place the two labels one next to the other.
private lazy var stackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.alignment = .center
stackView.axis = .horizontal
stackView.backgroundColor = .black
stackView.spacing = 10
return stackView
}()
// MARK: Labels
private lazy var firstLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.textColor = UIColor.brandColor(.white)
label.textAlignment = .right
label.font = UIFont.bloomSpeakFont(.titleUltraHeavy, ofSize: 8.0)
return label
}()
private lazy var secondLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.textColor = UIColor.brandColor(.white)
label.textAlignment = .right
label.font = UIFont.bloomSpeakFont(.bodyExtraBold, ofSize: 10.0)
return label
}()
// MARK: - Setup
private func setupStackView() {
stackView.addArrangedSubview(firstLabel)
//firstLabel.widthAnchor.constraint(equalToConstant: 100).isActive = true
//firstLabel.heightAnchor.constraint(equalToConstant: 100).isActive = true
//firstLabel.setContentHuggingPriority(UILayoutPriority.defaultLow, for: .horizontal)
stackView.addArrangedSubview(secondLabel)
//secondLabel.widthAnchor.constraint(equalToConstant: 100).isActive = true
//secondLabel.heightAnchor.constraint(equalToConstant: 100).isActive = true
//secondLabel.setContentHuggingPriority(UILayoutPriority.defaultHigh, for: .horizontal)
addSubview(stackView)
stackView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
stackView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}
My problem is:
What I want:
The label next to the number and also some padding some padding with the margins.
Thanks in advance.
EDIT
After set spacing to 0, numberOfLines to 1, stackView.alignment = .fill I got the result bellow. I just wonder how to add padding to the labels?

Thanks to the comments of #SandeepBhandari and #DonMag i could solved my issue:
The final solution was:
private lazy var stackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.alignment = .fill // << changed from .center to .fill
stackView.axis = .horizontal
stackView.backgroundColor = .black
//stackView.spacing = 10 << removed line
return stackView
}()
// MARK: Labels
private lazy var firstLabel: PaddingLabel = {
let label = PaddingLabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 1 // << changed from 0 to 1
label.textColor = UIColor.brandColor(.white)
label.textAlignment = .right
label.font = UIFont.bloomSpeakFont(.titleUltraHeavy, ofSize: 8.0)
return label
}()
private lazy var secondLabel: PaddingLabel = {
let label = PaddingLabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 1
label.textColor = UIColor.brandColor(.white)
label.textAlignment = .right
label.font = UIFont.bloomSpeakFont(.bodyExtraBold, ofSize: 10.0)
return label
}()
// MARK: - Setup
private func setupStackView() {
stackView.addArrangedSubview(firstLabel)
stackView.addArrangedSubview(secondLabel)
firstLabel.paddingLeft = 2
firstLabel.paddingRight = 1
secondLabel.paddingLeft = 1
secondLabel.paddingRight = 2
addSubview(stackView)
stackView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
stackView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}
I also use this guide https://johncodeos.com/how-to-add-padding-in-uilabel-in-ios-using-swift/, to add padding to the labels.
The final result is:

Related

Displaying property with Horizontal and Vertical Stack View in Swift

I am new to swift . I am following the programmatic approach to create the view . I created two stack view . One is horizontal and other one is vertical. Into horizontal stack view I want to display the label property and Vertical stack view I want to display the Image. I want to display the image on left side and label properties on right side.
Here is the code I used ..
import UIKit
class PeopleCell: UITableViewCell {
static let identifier = "PeopleCell"
private lazy var mainStackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.distribution = .fill
stackView.alignment = .leading
return stackView
}()
private lazy var stackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.distribution = .fill
stackView.alignment = .center
return stackView
}()
private lazy var lastnameTitleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.textAlignment = .center
return label
}()
private lazy var firstnameTitleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.textAlignment = .center
return label
}()
private lazy var peopleImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
// imageView.backgroundColor = .blue
return imageView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUpUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureCell(firstName: String, lastName: String) {
firstnameTitleLabel.text = "Firstname :\(firstName)"
lastnameTitleLabel.text = "Lastname : \(lastName)"
}
func configureImageCell(row: Int, viewModel: ViewModel) {
peopleImageView.image = nil
viewModel
.downloadImage(row: row) { [weak self] data in
let image = UIImage(data: data)
self?.peopleImageView.image = image
}
}
private func setUpUI() {
stackView.addArrangedSubview(lastnameTitleLabel)
stackView.addArrangedSubview(firstnameTitleLabel)
mainStackView.addArrangedSubview(peopleImageView)
mainStackView.addArrangedSubview(stackView)
contentView.addSubview(mainStackView)
// constraints
let safeArea = contentView.safeAreaLayoutGuide
mainStackView.topAnchor.constraint(equalTo: safeArea.topAnchor).isActive = true
mainStackView.bottomAnchor.constraint(equalTo: safeArea.bottomAnchor).isActive = true
mainStackView.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor, constant: 10).isActive = true
mainStackView.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor, constant: -10).isActive = true
peopleImageView.heightAnchor.constraint(equalToConstant: 140).isActive = true
peopleImageView.widthAnchor.constraint(equalToConstant: 140).isActive = true
stackView.leadingAnchor.constraint(equalTo: mainStackView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: mainStackView.trailingAnchor).isActive = true
}
}
Here is the screenshot ..
Here is the expected result.
The main problem is that you have your .axis properties reversed.
You want your mainStackView.axis to be .horizontal and your stackView.axis to be .vertical.
Also, these two lines are not needed (and cause problems):
// don't do this
//stackView.leadingAnchor.constraint(equalTo: mainStackView.leadingAnchor).isActive = true
//stackView.trailingAnchor.constraint(equalTo: mainStackView.trailingAnchor).isActive = true
As a side note, instead of:
let safeArea = contentView.safeAreaLayoutGuide
you may want to use:
let safeArea = contentView.layoutMarginsGuide
which gives you the default cell margins.
Edit
// this is the "main" stack view with
// the image on the left
// the labels on the right
// so it needs to be HORIZONTAL
private lazy var mainStackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
//stackView.axis = .vertical
stackView.axis = .horizontal
stackView.distribution = .fill
return stackView
}()
// this is the "labels" stack view with
// two (or more) labels from top down
// so it needs to be VERTICAL
private lazy var stackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
//stackView.axis = .horizontal
stackView.axis = .vertical
stackView.distribution = .fill
return stackView
}()

Can't figure out why my stackviews are not arranging vertically

I have done this many times but this time for some reason won't work the way it usually does. Am I doing something wrong here? I am just trying to get two views into my UIstackView and distribute them vertically. It seems to keep overlapping and going all over the place. At one point it was only even showing one view.
My viewdidload():
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
view.addSubview(headerView)
view.addSubview(contentView)
contentView.addSubview(contentStack)
headerView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.30).isActive = true
headerView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
headerView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
headerView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
contentView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.70).isActive = true
contentView.widthAnchor.constraint(equalTo: self.view.widthAnchor,multiplier: 0.90).isActive = true
contentView.topAnchor.constraint(equalTo: headerView.bottomAnchor,constant: 20).isActive = true
contentView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
}
My Views and Labels:
fileprivate lazy var headerView : UIView = {
var view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .black
return view
}()
fileprivate lazy var contentView : UIView = {
var view = UIView()
view.backgroundColor = .lightGray
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
fileprivate lazy var contentStack : UIStackView = {
var stack = UIStackView(arrangedSubviews: [EarningsView,ListingsView,])
stack.translatesAutoresizingMaskIntoConstraints = true
stack.distribution = .fillEqually
stack.alignment = .fill
stack.axis = .vertical
// stack.spacing = 5
return stack
}()
fileprivate lazy var EarningsView : UIView = {
let EarningsView = UIView()
EarningsView.translatesAutoresizingMaskIntoConstraints = false
EarningsView.backgroundColor = .blue
EarningsView.addSubview(EarningsLabel)
EarningsView.addViewBorder(borderColor: UIColor.black.cgColor, borderWith: 0.5, borderCornerRadius: 0.0)
return EarningsView
}()
fileprivate lazy var EarningsLabel : UILabel = {
let EarningsLabel = UILabel()
EarningsLabel.translatesAutoresizingMaskIntoConstraints = false
let earningsText = NSAttributedString(string: "My Earnings", attributes: self.stringAttrib)
EarningsLabel.attributedText = earningsText
EarningsLabel.textColor = .black
EarningsLabel.backgroundColor = .white
EarningsLabel.textAlignment = .center
return EarningsLabel
}()
fileprivate lazy var ListingsView : UIView = {
let ListingsView = UIView()
ListingsView.translatesAutoresizingMaskIntoConstraints = false
ListingsView.addSubview(ListingLabel)
ListingsView.addViewBorder(borderColor: UIColor.black.cgColor, borderWith: 0.5, borderCornerRadius: 0.0)
ListingsView.backgroundColor = .red
return ListingsView
}()
fileprivate lazy var ListingLabel : UILabel = {
let ListingLabel = UILabel()
ListingLabel.translatesAutoresizingMaskIntoConstraints = false
let listingText = NSAttributedString(string: "My Listing", attributes: self.stringAttrib)
ListingLabel.attributedText = listingText
return ListingLabel
}()
This is driving me crazy because I have done it so many times before and now I have spent atleast 6 hours on this little part trying to figure it out. Of course I could just create a whole new viewcontroller but I just want to figure this out.
EarningsView, EarningsLabel, ListingsView, ListingLabel have
translatesAutoresizingMaskIntoConstraints = false
But they have no constraints added to replace the Autoresizing constraints, so they just act goofy and go up to the top left. I've seen stuff like this before. On my stuff. Either autosize or put in constraints.

Is it possible to add constraint between two UILabels?

Yeah basically i want to create a constraint between the bottom border of one UILabel (label1) and top border of another UILabel (label2). I currently have the top of my label 1 connected to the safearea and constant height set up to 100.
let label1 = UILabel.init()
label1.text = "123"
view.addSubview(label1)
label1.translatesAutoresizingMaskIntoConstraints = false
label1.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
label1.heightAnchor.constraint(equalToConstant: 100).isActive = true
let label2 = UILabel.init()
label2.text = "456"
view.addSubview(label2)
label2.translatesAutoresizingMaskIntoConstraints = false
label2.topAnchor.constraint(???)
You need
let label1 = UILabel()
label1.text = "123"
view.addSubview(label1)
label1.translatesAutoresizingMaskIntoConstraints = false
let label2 = UILabel()
label2.text = "456"
view.addSubview(label2)
label2.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label1.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor,constant:20.0),
label1.centerXAnchor.constraint(equalTo:self.view.centerXAnchor),
label2.topAnchor.constraint(equalTo: self.label1.bottomAnchor,constant:20.0),
label2.centerXAnchor.constraint(equalTo:self.view.centerXAnchor)
])
You can also use a vertical UIStackView
Simply use vertical stackview .
let label1 = UILabel()
label1.text = "123"
let label2 = UILabel()
label2.text = "456"
let stackView = UIStackView(arrangedSubviews: [label1, label2])
stackView.axis = .vertical
stackView.distribution = .equalSpacing
stackView.alignment = .center
stackView.spacing = 10
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor,constant:20.0),
stackView.centerXAnchor.constraint(equalTo:self.view.centerXAnchor)
])

Programmatically create stack view

I am trying to create a date component by using a stack view programmatically. If user enters wrong date an error label will display message accordingly.Its working fine if I create it through storyboard, but when I use my programmatically created component which has added all elements in a stack view. I am not able to see error label.
I verified the autolayout I've added in storyboard and in my component class, both look similar. Here is code for my component.
class CustomDateView: UIView {
// MARK: - Variable
private let dayTextField: UITextField = {
let inputField = UITextField()
inputField.borderStyle = .none
inputField.layer.cornerRadius = 8.0
inputField.layer.borderColor = UIColor.darkGray.cgColor
inputField.backgroundColor = UIColor.blue
inputField.textAlignment = .center
inputField.tag = 0
inputField.translatesAutoresizingMaskIntoConstraints = false
return inputField
}()
private let monthTextField: UITextField = {
let inputField = UITextField()
inputField.borderStyle = .none
inputField.layer.cornerRadius = 8.0
inputField.layer.borderColor = UIColor.darkGray.cgColor
inputField.backgroundColor = UIColor.blue
inputField.textAlignment = .center
inputField.tag = 1
inputField.translatesAutoresizingMaskIntoConstraints = false
return inputField
}()
private let yearTextField: UITextField = {
let inputField = UITextField()
inputField.borderStyle = .none
inputField.layer.cornerRadius = 8.0
inputField.layer.borderColor = UIColor.darkGray.cgColor
inputField.backgroundColor = UIColor.blue
inputField.textAlignment = .center
inputField.tag = 2
inputField.translatesAutoresizingMaskIntoConstraints = false
return inputField
}()
private let errorLabel: UILabel = {
let errorLabel = UILabel()
errorLabel.textColor = .red
errorLabel.textAlignment = .center
errorLabel.numberOfLines = 0
errorLabel.translatesAutoresizingMaskIntoConstraints = false
return errorLabel
}()
private let monthSeparator: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private let yearSeparator: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private let horizontalStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.alignment = .fill
stackView.distribution = .fillProportionally
stackView.spacing = 16.0
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
private let verticalStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .fill
stackView.distribution = .fillProportionally
stackView.spacing = 8.0
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
// MARK: - Initialisers
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
// MARK: - Private Functions
private func setup() {
self.horizontalStackView.addArrangedSubview(self.dayTextField)
self.horizontalStackView.addArrangedSubview(self.monthSeparator)
self.horizontalStackView.addArrangedSubview(self.monthTextField)
self.horizontalStackView.addArrangedSubview(self.yearSeparator)
self.horizontalStackView.addArrangedSubview(self.yearTextField)
self.verticalStackView.addArrangedSubview(self.horizontalStackView)
self.verticalStackView.addArrangedSubview(self.errorLabel)
self.addSubview(self.verticalStackView)
self.translatesAutoresizingMaskIntoConstraints = false
let selfType = type(of: self)
NSLayoutConstraint.activate([
self.dayTextField.heightAnchor.constraint(equalToConstant: 48.0),
self.dayTextField.widthAnchor.constraint(equalToConstant: 62.0),
self.monthTextField.widthAnchor.constraint(equalToConstant: 62.0),
self.monthSeparator.widthAnchor.constraint(equalToConstant: 14.0),
self.yearSeparator.widthAnchor.constraint(equalToConstant: 14.0)
])
NSLayoutConstraint.activate([
self.verticalStackView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0.0),
self.verticalStackView.topAnchor.constraint(equalTo: self.topAnchor, constant: 0.0),
self.bottomAnchor.constraint(equalTo: self.verticalStackView.bottomAnchor),
self.trailingAnchor.constraint(equalTo: self.verticalStackView.trailingAnchor)
])
}
}
It render view correctly but after setting error label stack view won't grow to display the text.I have given fixed width to my separators and textfield's cause I want them to be of that exact width and height.
Is there any mistakes I'm making while applying autolayout in here.

Trying to make sense of UILabel behavior.

I am trying to replicate Apple's calculator UI layout.
Here is a gif of what I have so far.
The problems that I am encountering mostly have to do with the UILables.
As seen in the gif above, I am experiencing the following problems:
On device rotation, the labels "L1" and "L2" pop, instead of transitioning smoothly.
The labels on the brown colored buttons disappear when transitioning back to portrait.
For the labels "L1" and "L2" I have tried experimenting with the content mode and constraints, however, I still get clunky transitions.
As for the disappearing labels, instead of hiding/unhiding the stack view to make the layout appear and disappear via it's is hidden property, I instead tried using constraints on the stack view to handle the transition, however, the results remain the same.
I have also looked online and tried some suggestions, however, most answers were outdated or simply did not work.
The code is very straight forward, it primarily consists of setting up the views and its constraints.
extension UIStackView {
convenience init(axis: UILayoutConstraintAxis, distribution: UIStackViewDistribution = .fill) {
self.init()
self.axis = axis
self.distribution = distribution
self.translatesAutoresizingMaskIntoConstraints = false
}
}
class Example: UIView {
let mainStackView = UIStackView(axis: .vertical, distribution: .fill)
let subStackView = UIStackView(axis: .horizontal, distribution: .fillProportionally)
let portraitStackView = UIStackView(axis: .vertical, distribution: .fillEqually)
let landscapeStackView = UIStackView(axis: .vertical, distribution: .fillEqually)
var containerView: UIView = {
$0.backgroundColor = .darkGray
$0.translatesAutoresizingMaskIntoConstraints = false
return $0
}(UIView(frame: .zero))
let mainView: UIView = {
$0.backgroundColor = .blue
$0.translatesAutoresizingMaskIntoConstraints = false
return $0
}(UIView(frame: .zero))
let labelView: UIView = {
$0.backgroundColor = .red
$0.translatesAutoresizingMaskIntoConstraints = false
return $0
}(UIView(frame: .zero))
var labelOne: UILabel!
var labelTwo: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .red
autoresizingMask = [.flexibleWidth, .flexibleHeight]
labelOne = createLabel(text: "L1")
labelOne.translatesAutoresizingMaskIntoConstraints = false
labelOne.backgroundColor = .darkGray
labelTwo = createLabel(text: "L2")
labelTwo.translatesAutoresizingMaskIntoConstraints = false
labelTwo.backgroundColor = .black
landscapeStackView.isHidden = true
mainView.addSubview(labelView)
labelView.addSubview(labelOne)
labelView.addSubview(labelTwo)
addSubview(mainStackView)
mainStackView.addArrangedSubview(mainView)
setButtonStackView()
setStackViewConstriants()
setDisplayViewConstriants()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setStackViewConstriants() {
mainStackView.translatesAutoresizingMaskIntoConstraints = false
mainStackView.topAnchor.constraint(equalTo: topAnchor).isActive = true
mainStackView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
mainStackView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
mainStackView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
func setDisplayViewConstriants() {
mainView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 288/667).isActive = true
labelView.heightAnchor.constraint(equalTo: mainView.heightAnchor, multiplier: 128/288).isActive = true
labelView.centerYAnchor.constraint(equalTo: mainView.centerYAnchor).isActive = true
labelView.leadingAnchor.constraint(equalTo: mainView.leadingAnchor, constant: 24).isActive = true
labelView.trailingAnchor.constraint(equalTo: mainView.trailingAnchor, constant: -24).isActive = true
labelOne.heightAnchor.constraint(equalTo: labelTwo.heightAnchor, multiplier: 88/32).isActive = true
labelOne.trailingAnchor.constraint(equalTo: labelView.trailingAnchor).isActive = true
labelOne.leadingAnchor.constraint(equalTo: labelView.leadingAnchor).isActive = true
labelOne.topAnchor.constraint(equalTo: labelView.topAnchor).isActive = true
labelTwo.topAnchor.constraint(equalTo: labelOne.bottomAnchor).isActive = true
labelTwo.trailingAnchor.constraint(equalTo: labelView.trailingAnchor).isActive = true
labelTwo.leadingAnchor.constraint(equalTo: labelOne.leadingAnchor).isActive = true
labelTwo.bottomAnchor.constraint(equalTo: labelView.bottomAnchor).isActive = true
}
func createLabel(text: String) -> UILabel {
let label = UILabel(frame: .zero)
label.text = text
label.font = UIFont.init(name: "Arial-BoldMT", size: 60)
label.textColor = .white
label.textAlignment = .right
label.contentMode = .right
label.minimumScaleFactor = 0.1
label.adjustsFontSizeToFitWidth = true
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
return label
}
func createButton(text: String) -> UIButton {
let button = UIButton(type: .custom)
button.setTitle(text, for: .normal)
button.setTitleColor(.white, for: .normal)
button.layer.borderColor = UIColor.white.cgColor
button.layer.borderWidth = 1
button.titleLabel?.font = UIFont.init(name: "Arial-BoldMT", size: 60)
button.titleLabel?.minimumScaleFactor = 0.1
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.titleLabel?.translatesAutoresizingMaskIntoConstraints = false
button.titleLabel?.leadingAnchor.constraint(equalTo: button.leadingAnchor).isActive = true
button.titleLabel?.trailingAnchor.constraint(equalTo: button.trailingAnchor).isActive = true
button.titleLabel?.topAnchor.constraint(equalTo: button.topAnchor).isActive = true
button.titleLabel?.bottomAnchor.constraint(equalTo: button.bottomAnchor).isActive = true
button.titleLabel?.textAlignment = .center
button.titleLabel?.contentMode = .scaleAspectFill
button.titleLabel?.numberOfLines = 0
return button
}
func setButtonStackView() {
for _ in 1...5 {
let stackView = UIStackView(axis: .horizontal, distribution: .fillEqually)
for _ in 1...4 {
let button = createButton(text: "0")
button.backgroundColor = .brown
stackView.addArrangedSubview(button)
}
landscapeStackView.addArrangedSubview(stackView)
}
for _ in 1...5 {
let stackView = UIStackView(axis: .horizontal, distribution: .fillEqually)
for _ in 1...4 {
let button = createButton(text: "0")
button.backgroundColor = .purple
stackView.addArrangedSubview(button)
}
portraitStackView.addArrangedSubview(stackView)
}
subStackView.addArrangedSubview(landscapeStackView)
subStackView.addArrangedSubview(portraitStackView)
mainStackView.addArrangedSubview(subStackView)
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
if UIDevice.current.orientation.isLandscape && landscapeStackView.isHidden == true {
self.landscapeStackView.isHidden = false
}
if UIDevice.current.orientation.isPortrait && landscapeStackView.isHidden == false {
self.landscapeStackView.isHidden = true
}
self.layoutIfNeeded()
}
}
Overview:
Do things incrementally with separate components / view controllers (easier to debug)
The below solution is only for labels L1 and L2.
For the calculator buttons, it would be best to use a UICollectionViewController. (I haven't implemented it, add as a child view controller)
Code:
private func setupLabels() {
view.backgroundColor = .red
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .fill
stackView.distribution = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
let label1 = UILabel()
label1.text = "L1"
label1.textColor = .white
label1.backgroundColor = .darkGray
label1.textAlignment = .right
label1.font = UIFont.preferredFont(forTextStyle: .title1)
let label2 = UILabel()
label2.text = "L2"
label2.textColor = .white
label2.backgroundColor = .black
label2.textAlignment = .right
label2.font = UIFont.preferredFont(forTextStyle: .caption1)
stackView.addArrangedSubview(label1)
stackView.addArrangedSubview(label2)
}