Proper positioning of UIToolBar at the bottom of the screen - ios

Due to lack of practice with creating UIToolBar element, I don't fully understand what is the cleanest way to position UIToolBar at the bottom of the screen. Now my code looks like this:
private lazy var toolBar: UIToolbar = {
let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
toolBar.translatesAutoresizingMaskIntoConstraints = false
let addNewNote = UIBarButtonItem(barButtonSystemItem: .compose, target: toolBar, action: nil)
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: toolBar, action: nil)
toolBar.items = [spacer, addNewNote]
return toolBar
}()
private func setUpConstraints() {
NSLayoutConstraint.activate([
toolBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
toolBar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
toolBar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
])
}
This gives desired results, however I feel like I am missing a better way to implement this simple element. First of all, once the device is rotated, ToolBar doesn't fill all the space from leading to trailing, secondly assigning both leading/trailing constraints and width/height based on UIScreen.bounds property just doesn't seem right, although previously I saw a constraints layout issue of ToolBarElement in the console before I assigned this strange frame to my ToolBar. Now this issue is gone, but the situation did not become clearer.
My goal is to clone UIToolBar from iOS native notes app
So, as an experiences iOS developer (of course you are!) what would you recommend me to do?
Have a nice day!

If I understand well you can do it with autolayaout:
Declare your objects under your controller class:
let toolBar: UIToolbar = {
//let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)) // remove this
let toolBar = UIToolbar()
toolBar.translatesAutoresizingMaskIntoConstraints = false
let addNewNote = UIBarButtonItem(barButtonSystemItem: .compose, target: toolBar, action: nil)
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: toolBar, action: nil)
toolBar.tintColor = .yourColor
let toolBarTitleLabel = UILabel()
toolBarTitleLabel.text = "150 Results"
toolBarTitleLabel.sizeToFit()
toolBarTitleLabel.backgroundColor = .clear
toolBarTitleLabel.textColor = .white
toolBarTitleLabel.textAlignment = .center
let topBarButtonItemTitleLabel = UIBarButtonItem(customView: toolBarTitleLabel)
toolBar.items = [spacer, topBarButtonItemTitleLabel, spacer, addNewNote]
return toolBar
}()
let mylabel2: UILabel = {
let label = UILabel()
label.text = "Your results data text here..."
label.textAlignment = .center
label.textColor = .gray
label.font = .systemFont(ofSize: 16, weight: .regular)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let dummyView: UIView = {
let v = UIView()
v.backgroundColor = .systemBlue
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
In viewDidLoad set constraints:
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
view.addSubview(toolBar)
NSLayoutConstraint.activate([
toolBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
toolBar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
toolBar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
])
view.addSubview(mylabel2)
NSLayoutConstraint.activate([
mylabel2.bottomAnchor.constraint(equalTo: toolBar.topAnchor),
mylabel2.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 30),
mylabel2.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -30),
mylabel2.heightAnchor.constraint(equalToConstant: 50)
])
view.addSubview(dummyView)
NSLayoutConstraint.activate([
dummyView.bottomAnchor.constraint(equalTo: mylabel2.topAnchor),
dummyView.leadingAnchor.constraint(equalTo: mylabel2.leadingAnchor),
dummyView.trailingAnchor.constraint(equalTo: mylabel2.trailingAnchor),
dummyView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 30)
])
}
This is the result:

Related

How to animate a view to hide behind Navigation Bar

I'm trying to animate a view to hide behind the navigation bar.
The idea is the yellow label to appear from behind the green view.
I tried this modifying the top constraint to a negative number, but it works but if the yellow view is bigger than the green one it ends over the safe area.
My code:
#IBAction func buttonClick(_ sender: Any) {
UIView.animate(withDuration: 0.5) {
if(self.topMargin.constant<0){
self.topMargin.constant=0
}else {
self.topMargin.constant = -100
}
self.view.layoutIfNeeded()
}
}
Thats the result when hidden:
How can I achieve this effect without invading the safe zone?
setup your label under your Controller class:
let myLabel: UILabel = {
let label = UILabel()
label.text = "Label"
label.backgroundColor = .darkYellow
label.textAlignment = .center
label.textColor = .black
label.font = .systemFont(ofSize: 16, weight: .semibold)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
After that set two variables for label animation state:
var labelUp: NSLayoutConstraint!
var labeldown: NSLayoutConstraint!
In viewDidLoad setup your nav bar (I set it with my extension), present your label and constraints:
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "label UP", style: .plain, target: self, action: #selector(self.handleAnimate))
view.addSubview(myLabel)
labeldown = myLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
labeldown.isActive = true
labelUp = myLabel.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
myLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
myLabel.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
myLabel.heightAnchor.constraint(equalToConstant: 100).isActive = true
Now add a variable to control state of label and animation func:
var controlStatusLabel = true
#objc fileprivate func handleAnimate() {
switch controlStatusLabel {
case true:
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "label Down", style: .plain, target: self, action: #selector(self.handleAnimate))
self.labeldown.isActive = false
self.labelUp.isActive = true
self.view.layoutIfNeeded()
self.controlStatusLabel = false
}, completion: nil)
default:
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "label UP", style: .plain, target: self, action: #selector(self.handleAnimate))
self.labelUp.isActive = false
self.labeldown.isActive = true
self.view.layoutIfNeeded()
self.controlStatusLabel = true
}, completion: nil)
}
}
The result:
Embed your label (or whatever view you want to animate) in a "holder" view, constrained to the safe-area, with .clipsToBounds = true...
The holder view background will normally be clear -- I'm toggling it between clear and red so you can see it's frame.
Here'a quick example code for that:
class ViewController: UIViewController {
let label = UILabel()
let labelHolderView = UIView()
var labelTop: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Nav Bar"
// configure the label
label.textAlignment = .center
label.text = "I'm going to slide up."
label.backgroundColor = .systemYellow
// add it to the holder view
labelHolderView.addSubview(label)
// prevents label from showing outside the bounds
labelHolderView.clipsToBounds = true
label.translatesAutoresizingMaskIntoConstraints = false
labelHolderView.translatesAutoresizingMaskIntoConstraints = false
// add holder view to self.view
view.addSubview(labelHolderView)
// constant height for the label
let labelHeight: CGFloat = 160.0
// setup label top constraint
labelTop = label.topAnchor.constraint(equalTo: labelHolderView.topAnchor)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// activate label top constraint
labelTop,
// constrain label Leading/Trailing to holder
// we'll inset it by 20-points so we can see the holder view
label.leadingAnchor.constraint(equalTo: labelHolderView.leadingAnchor, constant: 20.0),
label.trailingAnchor.constraint(equalTo: labelHolderView.trailingAnchor, constant: -20.0),
// constant height
label.heightAnchor.constraint(equalToConstant: labelHeight),
// label gets NO Bottom constraint
// constrain holder to safe area
labelHolderView.topAnchor.constraint(equalTo: g.topAnchor),
labelHolderView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
labelHolderView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
// constant height (same as label height)
labelHolderView.heightAnchor.constraint(equalTo: label.heightAnchor),
])
// let's add a button to animate the label
// and one to show/hide the holder view
let btn1 = UIButton(type: .system)
btn1.setTitle("Animate It", for: [])
btn1.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(btn1)
let btn2 = UIButton(type: .system)
btn2.setTitle("Toggle Holder View Color", for: [])
btn2.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(btn2)
NSLayoutConstraint.activate([
// put the first button below the holder view
btn1.centerXAnchor.constraint(equalTo: g.centerXAnchor),
btn1.topAnchor.constraint(equalTo: labelHolderView.bottomAnchor, constant: 20.0),
// second button below it
btn2.centerXAnchor.constraint(equalTo: g.centerXAnchor),
btn2.topAnchor.constraint(equalTo: btn1.bottomAnchor, constant: 20.0),
])
// give the buttons an action
btn1.addTarget(self, action: #selector(animLabel(_:)), for: .touchUpInside)
btn2.addTarget(self, action: #selector(toggleHolderColor(_:)), for: .touchUpInside)
}
#objc func animLabel(_ sender: Any?) {
// animate the label up if it's down, down if it's up
labelTop.constant = labelTop.constant == 0 ? -label.frame.height : 0
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
})
}
#objc func toggleHolderColor(_ sender: Any?) {
labelHolderView.backgroundColor = labelHolderView.backgroundColor == .red ? .clear : .red
}
}

Swift - UIView moves when changing tab controller tabs

Inside the viewDidAppear I have a function that contains this code, in order to make a UIView:
let contentView = UIView()
func addSleepingView() {
contentView.backgroundColor = .systemYellow.withAlphaComponent(0.25)
view.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
contentView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
// Anchor your view right above the tabBar
contentView.bottomAnchor.constraint(equalTo: (tabBarController?.tabBar.topAnchor)!).isActive = true
contentView.heightAnchor.constraint(equalToConstant: 50).isActive = true
let label = UILabel()
label.text = "Test"
label.frame = CGRect(x: 0, y: 0, width: 25, height: 34.0)
label.lineBreakMode = .byWordWrapping
label.numberOfLines = 0
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(label)
label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
let button = UIButton()
button.setImage(UIImage(systemName: "arrow.clockwise", withConfiguration: UIImage.SymbolConfiguration(scale: .large)), for: UIControl.State.normal)
button.tintColor = .systemGray
button.frame = CGRect(x: self.view.bounds.width-42, y: 8, width: 34, height: 34.0)
button.isUserInteractionEnabled = true
button.addTarget(self, action: #selector(wakeupFunction), for: .touchUpInside)
contentView.addSubview(button)
let button2 = UIButton()
button2.setImage(UIImage(systemName: "exclamationmark.triangle", withConfiguration: UIImage.SymbolConfiguration(scale: .large)), for: UIControl.State.normal)
button2.tintColor = .label
button2.frame = CGRect(x: 8, y: 8, width: 34, height: 34.0)
button2.isUserInteractionEnabled = false
contentView.addSubview(button2)
contentView.bringSubviewToFront(button)
}
This is what it looks like:
Now this is exactly how I want it. The problem comes when I change tab. For example go to the last tab, and back to the first tab again. Then it looks like this:
What am I doing wrong here?
You can just add your code of activating constraints inside the DispatchQueue.main block
Updated Line you can change and it will start working as you're expectation.
// Anchor your view right above the tabBar
DispatchQueue.main.async
{
self.contentView.bottomAnchor.constraint(equalTo: (self.tabBarController?.tabBar.topAnchor)!).isActive = true
self.contentView.heightAnchor.constraint(equalToConstant: 50).isActive = true
}

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:

uiview over uinavigationcontroller

I have a problem when adding uiview under navigation controller. why my uiview is on top of uinavigationcontroller, I want to add my uiview under navigationController. this is my code.
let slideView = UIView()
view.backgroundColor = .white
navigationItem.title = "Absensi"
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.barTintColor = .white
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.font: UIFont(name: "NunitoSans-SemiBold", size: 20)]
navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "ic-back-line").withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(handleBack))
view.addSubview(slideView)
slideView.backgroundColor = .red
slideView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
slideView.topAnchor.constraint(equalTo: view.topAnchor),
slideView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
slideView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
slideView.heightAnchor.constraint(equalToConstant: 80)
])
Set your constraints with respect to safe area.
You should be add the topAnchor to safe area -> view.safeAreaLayoutGuide.topAnchor
NSLayoutConstraint.activate([
slideView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
slideView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
slideView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
slideView.heightAnchor.constraint(equalToConstant: 80)
])
just try using frame instead of constraint..this code should work
override func viewDidAppear(_ animated: Bool) {
let slideView = UIView(frame: CGRect(x: 0, y:
navigationController?.navigationBar.frame.height ?? 0 + 20 ,width: UIScreen.main.bounds.width, height: 80))
slideView.backgroundColor = .red
slideView.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .white
navigationItem.title = "Absensi"
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.barTintColor = .white
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.font: UIFont(name: "NunitoSans-SemiBold", size: 20)]
navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "ic-back-line").withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(handleBack))
view.addSubview(slideView)
}

Constraints for two UIStackView - one under the other

I working on "Hangman" app. On the top I want image, in middle textfield, and bottom couple UIStackView row for letters. Now I try to add constraints for only two UIStackView one under the other, but one is always behind other ie. not see.
This is image where you can se only second stack view (named: stacklView2), and the first i cant see. Why? What I doing wrong?
And this is code:
import UIKit
class ViewController: UIViewController {
var imageView: UIImageView!
var answerTextfield: UITextField!
override func loadView() {
view = UIView()
view.backgroundColor = .white
imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
imageView.layer.borderWidth = 1
view.addSubview(imageView)
answerTextfield = UITextField()
answerTextfield.translatesAutoresizingMaskIntoConstraints = false
answerTextfield.textAlignment = .center
answerTextfield.isUserInteractionEnabled = false
answerTextfield.layer.borderWidth = 1
view.addSubview(answerTextfield)
let button1 = UIButton()
button1.backgroundColor = .red
let button2 = UIButton()
button2.backgroundColor = .blue
let stackView1 = UIStackView(arrangedSubviews: [button1, button2])
stackView1.translatesAutoresizingMaskIntoConstraints = false
stackView1.distribution = .fillEqually
stackView1.axis = .horizontal
view.addSubview(stackView1)
let stackView2 = UIStackView(arrangedSubviews: [button2, button1])
stackView2.translatesAutoresizingMaskIntoConstraints = false
stackView2.distribution = .fillEqually
stackView2.axis = .horizontal
view.addSubview(stackView2)
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor, constant: 5),
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
answerTextfield.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 20),
answerTextfield.widthAnchor.constraint(equalTo: view.layoutMarginsGuide.widthAnchor, multiplier: 0.5),
answerTextfield.centerXAnchor.constraint(equalTo: view.centerXAnchor),
stackView1.topAnchor.constraint(equalTo: answerTextfield.bottomAnchor, constant: 20),
stackView1.widthAnchor.constraint(equalTo: view.layoutMarginsGuide.widthAnchor, multiplier: 1.0),
stackView1.centerXAnchor.constraint(equalTo: view.layoutMarginsGuide.centerXAnchor),
//stackView1.bottomAnchor.constraint(equalTo: stackView2.layoutMarginsGuide.topAnchor, constant: -5),
stackView2.topAnchor.constraint(equalTo: stackView1.bottomAnchor, constant: 20),
stackView2.widthAnchor.constraint(equalTo: view.layoutMarginsGuide.widthAnchor, multiplier: 1.0),
stackView2.centerXAnchor.constraint(equalTo: view.layoutMarginsGuide.centerXAnchor),
stackView2.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor, constant: -5),
])
}
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = UIImage(named: "Hangman-0")
answerTextfield.text = "T E X T F I E L D"
setupNavigationBar()
}
func setupNavigationBar() {
let hintButton = UIButton(type: .infoLight)
hintButton.addTarget(self, action: #selector(hintTapped), for: .touchUpInside)
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: hintButton)
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(newGameTapped))
}
#objc func hintTapped() {
print("Hint button tapped!")
}
#objc func newGameTapped() {
print("New Game button tapped!")
}
}
You use same objects button1 and button2 in both stacks
let stackView1 = UIStackView(arrangedSubviews: [button1, button2])
let stackView2 = UIStackView(arrangedSubviews: [button2, button1])
so it's added to stackView2 only you need to create 2 other different ones as a single element can be added to only 1 view

Resources