Update a label's text in a UIStackView and while keeping the text centered? - ios

When I place a label with centered text in a stack view, then update the text, it no longer appears centered.
import PlaygroundSupport
import UIKit
let stackView = UIStackView(frame: CGRect(origin: .zero, size: CGSize(width: 100, height: 20)))
let label = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 100, height: 20)))
label.text = "Hello"
label.textAlignment = .center
stackView.addArrangedSubview(label)
label.text = "World"
PlaygroundPage.current.liveView = stackView
The expected outcome is that "World" is centered. However, it appears leftaligned. Calling layoutSubviews() did not help.

Stack views don't play well without auto-layout - particularly in Playgrounds.
Try it like this:
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white
let stackView = UIStackView()
let label = UILabel()
label.text = "Hello"
label.textAlignment = .center
// so we can see the frame
label.backgroundColor = .green
stackView.addArrangedSubview(label)
label.text = "World"
view.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.widthAnchor.constraint(equalToConstant: 100.0),
stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
stackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20.0),
])
self.view = view
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

Related

I want to set label & Imageview in centre of myView but App crashing after adding some constraints

Error:-
Thread 1: "Unable to activate constraint with anchors <NSLayoutXAxisAnchor:0x280af8500 \"UILabel:0x103dc4fa0.centerX\"> and <NSLayoutXAxisAnchor:0x280af89c0 \"UIView:0x103dc49d0.centerX\"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal."
I've created a function programmatical in Base view controller which returns a view & I've added some constraints to its
Function:-
func getMarker (lbl:String, img:UIImage) -> UIView {
let myView = UIView(frame: CGRect.zero)
myView.center = CGPoint(x: 50, y: 160)
myView.backgroundColor = UIColor.clear
let imageView = UIImageView(image: img)
imageView.frame = CGRect(x: 0, y: 0, width: 20, height: 40)
myView.addSubview(imageView)
let label = UILabel(frame: CGRect(x: 0, y: 45, width: 120, height: 30))
label.text = lbl
label.textAlignment = .center
label.adjustsFontSizeToFitWidth = true
label.textColor = UIColor.black
label.backgroundColor = UIColor.white
label.layer.borderColor = UIColor.lightGray.cgColor
label.layer.borderWidth = 0.5
label.layer.cornerRadius = 5
label.layer.masksToBounds = true
label.sizeToFit()
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
imageView.centerXAnchor.constraint(equalTo: myView.centerXAnchor)
])
myView.addSubview(label)
return myView
}
calling function in another controller but it crashing and showing me the error which I mentioned above
Calling function:-
getMarker(lbl: device.name ?? "", img: (UIImage(named: icfile) ?? UIImage(named: "truck_1_orange")!))
U need to add subview first, then activate layout. Label is not in myView subviews in your code. It is not in any hierarchy at the moment of layout constraint activation.
myView.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
imageView.centerXAnchor.constraint(equalTo: myView.centerXAnchor)
])
You need to configure the layout of your subviews (imageView and label) in order to have them sized and positioned where you want them.
Take a look at this example code:
class MarkerVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBlue
guard let img = UIImage(named: "img80x80")
else {
fatalError("Could not load sample image!!!")
}
let markerView1 = getMarker(lbl: "Testing", img: img)
let markerView2 = getMarkerAutoSized(lbl: "Testing", img: img)
markerView1.translatesAutoresizingMaskIntoConstraints = false
markerView2.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(markerView1)
view.addSubview(markerView2)
// respect safe area
let safeG = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// we have to set both Position and Size constraints
// for markerView1
markerView1.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 20.0),
markerView1.widthAnchor.constraint(equalToConstant: 240.0),
markerView1.heightAnchor.constraint(equalToConstant: 100.0),
markerView1.centerXAnchor.constraint(equalTo: view.centerXAnchor),
// markerView2 uses its subviews to set its own size
// so we only need position constraints
markerView2.topAnchor.constraint(equalTo: markerView1.bottomAnchor, constant: 20.0),
markerView2.centerXAnchor.constraint(equalTo: view.centerXAnchor),
])
// so we can see the view frames
markerView1.backgroundColor = .systemRed
markerView2.backgroundColor = .systemRed
}
func getMarker (lbl:String, img:UIImage) -> UIView {
let myView = UIView()
myView.backgroundColor = UIColor.clear
let imageView = UIImageView(image: img)
let label = UILabel()
label.text = lbl
label.textAlignment = .center
label.adjustsFontSizeToFitWidth = true
label.textColor = UIColor.black
label.backgroundColor = UIColor.white
label.layer.borderColor = UIColor.lightGray.cgColor
label.layer.borderWidth = 0.5
label.layer.cornerRadius = 5
label.layer.masksToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
myView.addSubview(imageView)
myView.addSubview(label)
NSLayoutConstraint.activate([
// image view Width and Height
imageView.widthAnchor.constraint(equalToConstant: 20.0),
imageView.heightAnchor.constraint(equalToConstant: 40.0),
// labe Width and Height
label.widthAnchor.constraint(equalToConstant: 120.0),
label.heightAnchor.constraint(equalToConstant: 30.0),
// image view aligned to Top
imageView.topAnchor.constraint(equalTo: myView.topAnchor),
// centered Horizontally
imageView.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
// label 5-pts below image view
label.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 5.0),
// centered Horizontally
label.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
])
return myView
}
func getMarkerAutoSized (lbl:String, img:UIImage) -> UIView {
let myView = UIView()
myView.backgroundColor = UIColor.clear
let imageView = UIImageView(image: img)
let label = UILabel()
label.text = lbl
label.textAlignment = .center
label.adjustsFontSizeToFitWidth = true
label.textColor = UIColor.black
label.backgroundColor = UIColor.white
label.layer.borderColor = UIColor.lightGray.cgColor
label.layer.borderWidth = 0.5
label.layer.cornerRadius = 5
label.layer.masksToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
myView.addSubview(imageView)
myView.addSubview(label)
NSLayoutConstraint.activate([
// image view Width and Height
imageView.widthAnchor.constraint(equalToConstant: 20.0),
imageView.heightAnchor.constraint(equalToConstant: 40.0),
// labe Width and Height
label.widthAnchor.constraint(equalToConstant: 120.0),
label.heightAnchor.constraint(equalToConstant: 30.0),
// image view aligned to Top
imageView.topAnchor.constraint(equalTo: myView.topAnchor),
// centered Horizontally
imageView.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
// label 5-pts below image view
label.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 5.0),
// centered Horizontally
label.centerXAnchor.constraint(equalTo: myView.centerXAnchor),
// to auto-size myView
label.leadingAnchor.constraint(equalTo: myView.leadingAnchor),
label.trailingAnchor.constraint(equalTo: myView.trailingAnchor),
label.bottomAnchor.constraint(equalTo: myView.bottomAnchor),
])
return myView
}
}
I modified your getMarker(...) func to size and position the subviews.
I also added a very similar getMarkerAutoSized(...) func that uses a couple additional constraints on the subviews.
For the first version, we must set both the Position and Size of the generated view.
For the second version, we only need to set the generated view's Position because it sizes itself to fit its subviews.
Here's how they look:

Swift: Programmatic Autolayout broken by UNavigationController

I have inherited a UIKit app where my predecessor has written all the interface code by hand. I have a view controller, a simple login screen that works just fine, but when I add it to a UINavigationController it is oddly stretched. This doesn't make a lot of sense to me.
I feel like I must be missing some simple flag, or what do I need to do to make the Navcontroller play nice with this programmatic autolayout (which is hopefully my last ever)
// this a view controller extension
func apply(constraints: [NSLayoutConstraint]) {
translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate(constraints)
}
There's my handy dandy, seemingly sane utility for applying constraints. As an example, the nice little oval thing making my password textfield looks nice has these constraints set up.
// these constraints are being setup in the view controller
emailCapsuleView.apply(constraints: [
emailCapsuleView.topAnchor.constraint(equalTo: subBigTitle.bottomAnchor, constant: 24.0),
emailCapsuleView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
emailCapsuleView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8),
emailCapsuleView.heightAnchor.constraint(equalToConstant: Dimensions.inputFieldHeight)
])
Outside of a UINavigationController everything is fine,
but in a UINavigationController everythhing is super wide and broken (simulator shot)
The width is not the problem here - if I use a constant for the width, my subview is still off center despite having it's centerX sets to the view controller's view's center X.
Configure your navigation controller and after that try like this:
set your objects:
let emailTextfield: UITextField = {
let tf = UITextField()
tf.backgroundColor = .white
tf.layer.borderWidth = 1
tf.layer.borderColor = UIColor.lightGray.cgColor
tf.setPadding(left: 10, right: 10)// use my extension below
tf.attributedPlaceholder = NSAttributedString(string: "Email address", attributes: [.foregroundColor: UIColor.lightGray])
tf.layer.cornerRadius = 14
tf.clipsToBounds = true
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()
let passTextfield: UITextField = {
let tf = UITextField()
tf.backgroundColor = .white
tf.layer.borderWidth = 1
tf.layer.borderColor = UIColor.lightGray.cgColor
tf.setPadding(left: 10, right: 10)// use my extension below
tf.attributedPlaceholder = NSAttributedString(string: "Password", attributes: [.foregroundColor: UIColor.lightGray])
tf.layer.cornerRadius = 14
tf.clipsToBounds = true
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()
let loginButton: UIButton = {
let b = UIButton(type: .system)
b.backgroundColor = .black
b.setTitle("Save Image", for: .normal)
b.titleLabel?.font = .systemFont(ofSize: 16, weight: .semibold)
b.setTitleColor(.white, for: .normal)
b.layer.cornerRadius = 14
b.clipsToBounds = true
b.translatesAutoresizingMaskIntoConstraints = false
return b
}()
let subBigTitle: UILabel = {
let l = UILabel()
l.text = "Your Big Title"
l.font = .systemFont(ofSize: 30, weight: .regular)
l.textColor = .black
l.textAlignment = .center
l.translatesAutoresizingMaskIntoConstraints = false
return l
}()
Now in viewDidLoad set stackView, bigTitle label and constraints:
view.addSubview(subBigTitle)
subBigTitle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
subBigTitle.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
subBigTitle.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
subBigTitle.heightAnchor.constraint(equalToConstant: 60).isActive = true
let stackView = UIStackView(arrangedSubviews: [emailTextfield, passTextfield, loginButton])
stackView.axis = .vertical
stackView.distribution = .fillEqually
stackView.spacing = 10
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
stackView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8).isActive = true
stackView.heightAnchor.constraint(equalToConstant: 170).isActive = true
stackView.topAnchor.constraint(equalTo: subBigTitle.bottomAnchor, constant: 24).isActive = true
stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
to add text padding to your textfield use my extension:
extension UITextField {
func setPadding(left: CGFloat, right: CGFloat){
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: left, height: self.frame.size.height))
self.leftView = paddingView
self.leftViewMode = .always
let paddingViewRight = UIView(frame: CGRect(x: 0, y: 0, width: right, height: self.frame.size.height))
self.rightView = paddingViewRight
self.rightViewMode = .always
}
}
and this is the result:

How can I add padding (and a background) to a UILabel

This has been asked before on Stackoverflow but the solutions don't work for me.
I'm building an app in SwiftUI but I need to use MapKit for maps, so I'm creating some views in UIKit (programmatically, no interface builder). My current problem is that I want to make a capsule background with some padding around a UILabel. It needs to accommodate arbitrary text, so I can't hardcode the sizes, but I can't find a way to determine the innate size of the UILabel text at runtime. I've tried UIEdgeInsets without success.
In the attached code, I am showing a SwiftUI version of what I'm trying to achieve, and then the UIKit attempt. I'd like to follow best practices, so please feel free to tell me any better ways of achieving this.
(Screenshot of what the code produces)
import SwiftUI
struct SwiftUICapsuleView: View {
var body: some View {
Text("Hello, World!")
.padding(6)
.background(Color.gray)
.cornerRadius(15)
}
}
struct UIKitCapsuleView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
let label = UILabel(frame: .zero)
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 17)
label.text = "Goodbye, World!"
label.layer.cornerRadius = 15
label.layer.backgroundColor = UIColor.gray.cgColor
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
label.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
label.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
return view
}
func updateUIView(_ view: UIView, context: Context) {
}
}
struct ExperimentView_Previews: PreviewProvider {
static var previews: some View {
VStack {
SwiftUICapsuleView()
UIKitCapsuleView()
}
}
}
You probably want to set the background color and rounded corners of the view, not the label.
You also should use a full set of constraints.
Give this a try:
struct UIKitCapsuleView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
// set the view's background color
view.backgroundColor = .cyan
// set the cornerRadius on the view's layer
view.layer.cornerRadius = 15
let label = UILabel(frame: .zero)
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 17)
label.text = "Goodbye, World!"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
// you can adjust padding here
let padding: CGFloat = 6
// use full constraints
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: view.topAnchor, constant: padding),
label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: padding),
label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -padding),
label.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -padding),
])
return view
}
func updateUIView(_ view: UIView, context: Context) {
}
}

How to center two views in super view with greater than or equal to constraints

I made an example ViewController with two Labels to highlight my issue. The goal is to vertically separate the labels by 10, and then center them vertically using greater than or equal to constraints. I'm using visual format, but this should apply if I setup my constraints like view.topAnchor.constraint(greaterThan.... I also have two constraints to horizontally layout the labels
My ViewController:
class myVC: UIViewController {
lazy var titleLabel: UILabel = {
let l = UILabel(frame: .zero)
l.translatesAutoresizingMaskIntoConstraints = false
l.text = "Hello World"
l.font = .systemFont(ofSize: 50)
l.textColor = .black
return l
}()
lazy var descLabel: UILabel = {
let l = UILabel(frame: .zero)
l.translatesAutoresizingMaskIntoConstraints = false
l.text = "description"
l.font = .systemFont(ofSize: 35)
l.textColor = .gray
return l
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
view.addSubview(titleLabel)
view.addSubview(descLabel)
titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
descLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor).isActive = true
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-(<=50)-[titleLabel]-(10)-[descLabel]-(<=50)-|", options: .init(), metrics: nil, views: ["titleLabel": titleLabel, "descLabel": descLabel]))
}
}
This results in . From my understanding, this SHOULD separate the views by 10 pts, and center the labels vertically because in the format "V:|-(<=50)-[titleLabel]-(10)-[descLabel]-(<=50)-|" I say that the distance between the Title Label's top and the superView's top should be at least (greaterThanOrEqualTo) 50, and the distance between the description Label's bottom and the superView's bottom should be at least 50. What should my top and bottom constraints look like if I want to center the two labels vertically?
Yes, I realize I can just set vertical and horizontal centers, but this is an example I made for a problem I can't use those for. I need to be able to center the View with greater(or less) than or equal to constraints.
It's very difficult to center elements using VFL.
It's also difficult to center two elements unless they are embedded in a UIView or a UIStackView.
Here is one option by embedding the labels in a "container" UIView:
class MyVC: UIViewController {
lazy var titleLabel: UILabel = {
let l = UILabel(frame: .zero)
l.translatesAutoresizingMaskIntoConstraints = false
l.text = "Hello World"
l.font = .systemFont(ofSize: 50)
l.textColor = .black
// center the text in the label - change to .left if desired
l.textAlignment = .center
return l
}()
lazy var descLabel: UILabel = {
let l = UILabel(frame: .zero)
l.translatesAutoresizingMaskIntoConstraints = false
l.text = "description"
l.font = .systemFont(ofSize: 35)
l.textColor = .gray
// center the text in the label - change to .left if desired
l.textAlignment = .center
return l
}()
lazy var containerView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
// give the labels and containerView background colors to make it easy to see the layout
titleLabel.backgroundColor = .green
descLabel.backgroundColor = .cyan
containerView.backgroundColor = .blue
// add containerView to view
view.addSubview(containerView)
// add labels to containerView
containerView.addSubview(titleLabel)
containerView.addSubview(descLabel)
NSLayoutConstraint.activate([
// constrain titleLabel Top to containerView Top
titleLabel.topAnchor.constraint(equalTo: containerView.topAnchor),
// constrain titleLabel Leading and Trailing to containerView Leading and Trailing
titleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
titleLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
// constrain descLabel Leading and Trailing to containerView Leading and Trailing
descLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
descLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
// constrain descLabel Bottom to containerView Bottom
descLabel.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
// constrain descLabel Top 10-pts from titleLabel Bottom
descLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10.0),
// constrain containerView centered horizontally and vertically
containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
containerView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
}
Result:
This can be achieved easily by using stackview. Add both the labels in stackview and center it vertically in the superview with all other constraints(top, leading, bottom, trailing).
Here is the sample code of view controller for your use-case.
class ViewController: UIViewController {
lazy var titleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Hello \nWorld"
label.font = .systemFont(ofSize: 50)
label.backgroundColor = .orange
label.numberOfLines = 0
label.textColor = .black
return label
}()
lazy var descLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "a\n b\n c\n"
label.font = .systemFont(ofSize: 35)
label.backgroundColor = .green
label.numberOfLines = 0
label.textColor = .gray
return label
}()
lazy var contentView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.spacing = 10
stackView.distribution = .fill
return stackView
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
contentView.addArrangedSubview(titleLabel)
contentView.addArrangedSubview(descLabel)
self.view.addSubview(contentView)
let constraints = [
contentView.topAnchor.constraint(greaterThanOrEqualTo: view.safeAreaLayoutGuide.topAnchor),
contentView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
contentView.bottomAnchor.constraint(lessThanOrEqualTo: view.safeAreaLayoutGuide.bottomAnchor)
]
NSLayoutConstraint.activate(constraints)
}
}
The above code will result this view and it goes on to take the top and buttom space until it meets the safeArea. Moreover you can set the vertical content hugging and compression resistance priority to control which label to expand or shrink.

Achieving padding from SwiftUI to UIViews

In SwiftUI, you could easily achieving padding via the following code:
Text("Hello World!")
.padding(20)
What options do I have to achieve the same in UIKit?
You can use storyboard for same and easily make this layout by combining UIView and Label.
Just add once view in view controller and centre align vertically and horizontally. Then add label inside that view and set top, bottom, leading, trailing to 20 respective to that view.
Just check following image.
This will make exactly same output as you want.
Using a UIStackView, something like this:
class PaddingableView: UIView {
var padding = UIEdgeInsets.zero { didSet { contentStackView.layoutMargins = padding } }
// MARK: Subviews
private lazy var contentStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.alignment = .fill
stackView.distribution = .fill
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = padding
return stackView
}()
// MARK: Functions
private func addContentStackView() {
super.addSubview(contentStackView)
NSLayoutConstraint.activate([
contentStackView.topAnchor.constraint(equalTo: topAnchor),
contentStackView.bottomAnchor.constraint(equalTo: bottomAnchor),
contentStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
contentStackView.trailingAnchor.constraint(equalTo: trailingAnchor)
])
}
override func addSubview(_ view: UIView) {
contentStackView.addArrangedSubview(view)
}
override func layoutSubviews() {
if contentStackView.superview == nil { addContentStackView() }
super.layoutSubviews()
}
}
Note that using too many nested stackviews can hit the performance
Ok, most simple is of corse Storyboard-based approach (as shown by #Sagar_Chauhan)...
Below is provided line-by-line Playground variant (as to compare with SwiftUI Preview by lines of code, for instance).
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
override func loadView() {
let view = UIView(frame: CGRect(x: 0, y: 0, width: 375, height: 677))
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .white
self.view = view
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Hello World!"
label.textColor = .black
label.backgroundColor = .yellow
label.textAlignment = .center
self.view.addSubview(label)
let fitSize = label.sizeThatFits(view.bounds.size)
label.widthAnchor.constraint(equalToConstant: fitSize.width + 12.0).isActive = true
label.heightAnchor.constraint(equalToConstant: fitSize.height + 12.0).isActive = true
label.topAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
label.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
}
}
PlaygroundPage.current.liveView = MyViewController()

Resources