I'm new to setting up StackViews and Buttons programmatically. I am getting some strange behavior with my constraints I cannot figure out what I'm doing wrong. It feels like I'm missing something simple. Any help is greatly appreciated!
I am trying to add two buttons to a StackView to create a custom tab bar. However, when I add the constraints to the buttons they are showing up outside the bottom of StackView. It's like the top constraint of Earth image isn't working. Any ideas? See image and code below.
// View to put in the StackView
class ProfileBottomTabBarView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.translatesAutoresizingMaskIntoConstraints = false
self.backgroundColor = .blue
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// Calculate the screen height
public var screenHeight: CGFloat {
return UIScreen.main.bounds.height
}
// StackView height set to a proporation of screen height
let stackViewHeight = screenHeight * 0.07
// Views to put in the StackView
let profileIconView = ProfileBottomTabBarView()
let actIconView = ActBottomTabBarView()
let achieveIconView = AchieveBottomTabBarView()
let growIconView = GrowBottomTabBarView()
// Buttons to put in the Views
let profileButton = UIButton(type: .system)
let actButton = UIButton(type: .system)
let achieveButton = UIButton(type: .system)
let growButton = UIButton(type: .system)
let profileButtonText = UIButton(type: .system)
let actButtonText = UIButton(type: .system)
let achieveButtonText = UIButton(type: .system)
let growButtonText = UIButton(type: .system)
// Stackview setup
lazy var stackView: UIStackView = {
let stackV = UIStackView(arrangedSubviews: [profileIconView, actIconView, achieveIconView, growIconView])
stackV.translatesAutoresizingMaskIntoConstraints = false
stackV.axis = .horizontal
stackV.spacing = 20
stackV.distribution = .fillEqually
return stackV
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
// Add StackView
view.addSubview(stackView)
stackView.bottomAnchor.constraint(equalTo: view.safeBottomAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: view.safeLeadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.safeTrailingAnchor).isActive = true
// Set height of the bottom tab bar as a proportion of the screen height.
stackView.heightAnchor.constraint(equalToConstant: stackViewHeight).isActive = true
profileIconView.topAnchor.constraint(equalTo: stackView.topAnchor).isActive = true
profileIconView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor).isActive = true
profileIconView.heightAnchor.constraint(equalToConstant: stackViewHeight).isActive = true
// Add Buttons to the View
profileIconView.addSubview(profileButton)
profileIconView.addSubview(profileButtonText)
profileButton.translatesAutoresizingMaskIntoConstraints = false
profileButtonText.translatesAutoresizingMaskIntoConstraints = false
// Profile Button with Earth Image Setup
profileButton.setImage(UIImage(named: "earthIcon"), for: .normal)
profileButton.imageView?.contentMode = .scaleAspectFit
profileButton.topAnchor.constraint(equalTo: profileIconView.topAnchor).isActive = true
profileButton.bottomAnchor.constraint(equalTo: profileButtonText.topAnchor).isActive = true
profileButton.centerXAnchor.constraint(equalTo: profileIconView.centerXAnchor).isActive = true
//Set height of icon to a proportion of the stackview height
let profileButtonHeight = stackViewHeight * 0.8
profileButton.heightAnchor.constraint(equalTo: profileIconView.heightAnchor, constant: profileButtonHeight).isActive = true
profileButton.widthAnchor.constraint(equalToConstant: profileButtonHeight).isActive = true
profileButton.imageView?.widthAnchor.constraint(equalToConstant: profileButtonHeight)
profileButton.imageView?.heightAnchor.constraint(equalToConstant: profileButtonHeight)
// Profile Text Button Setup
profileButtonText.setTitle("Profile", for: .normal)
profileButtonText.titleLabel?.font = UIFont.boldSystemFont(ofSize: 12)
profileButtonText.setTitleColor(.white, for: .normal)
profileButtonText.topAnchor.constraint(equalTo: profileButton.bottomAnchor).isActive = true
profileButtonText.bottomAnchor.constraint(equalTo: profileIconView.bottomAnchor).isActive = true
profileButtonText.centerXAnchor.constraint(equalTo: profileIconView.centerXAnchor).isActive = true
//Set height of icon to a proportion of the stackview height
let profileButtonTextHeight = stackViewHeight * 0.2
profileButton.heightAnchor.constraint(equalTo: profileIconView.heightAnchor, constant: profileButtonTextHeight).isActive = true
profileButtonText.widthAnchor.constraint(equalToConstant: 40).isActive = true
}