Несколько вещей не так с вашими ограничениями ...
Вы вычисляете высоту / ширину и используете их в качестве констант, но эти значения могут (почти наверняка) изменяться в зависимости от жизненного цикла представления.
Лучше использовать только связанные ограничения.Например:
// constrain profile image button top, centerX and width relative to the iconView
profileButton.topAnchor.constraint(equalTo: profileIconView.topAnchor),
profileButton.centerXAnchor.constraint(equalTo: profileIconView.centerXAnchor),
profileButton.widthAnchor.constraint(equalTo: profileIconView.widthAnchor, multiplier: 1.0),
// constrain profile text button bottom, centerX and width relative to the iconView
profileButtonText.centerXAnchor.constraint(equalTo: profileIconView.centerXAnchor),
profileButtonText.widthAnchor.constraint(equalTo: profileIconView.widthAnchor, multiplier: 1.0),
profileButtonText.bottomAnchor.constraint(equalTo: profileIconView.bottomAnchor),
// constrain bottom of image button to top of text button (with a padding of 4-pts, change to suit)
profileButton.bottomAnchor.constraint(equalTo: profileButtonText.topAnchor, constant: -4.0),
// constrain height of text button to 20% of height of iconView
profileButtonText.heightAnchor.constraint(equalTo: profileIconView.heightAnchor, multiplier: 0.2),
Чтобы упростить себе задачу, я бы предложил создать BottomTabBarView
, который обрабатывает добавление и ограничение ваших кнопок:
class BottomTabBarView: UIView {
var theImageButton: UIButton = {
let v = UIButton()
v.translatesAutoresizingMaskIntoConstraints = false
v.imageView?.contentMode = .scaleAspectFit
return v
}()
var theTextButton: UIButton = {
let v = UIButton()
v.translatesAutoresizingMaskIntoConstraints = false
v.titleLabel?.font = UIFont.boldSystemFont(ofSize: 12)
v.setTitleColor(.white, for: .normal)
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
convenience init(withImageName imageName: String, labelText: String, bkgColor: UIColor) {
self.init()
self.commonInit()
theImageButton.setImage(UIImage(named: imageName), for: .normal)
theTextButton.setTitle(labelText, for: .normal)
backgroundColor = bkgColor
}
func commonInit() -> Void {
self.translatesAutoresizingMaskIntoConstraints = false
addSubview(theImageButton)
addSubview(theTextButton)
NSLayoutConstraint.activate([
// constrain profile image button top, centerX and width of the iconView
theImageButton.topAnchor.constraint(equalTo: topAnchor),
theImageButton.centerXAnchor.constraint(equalTo: centerXAnchor),
theImageButton.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1.0),
// constrain profile text button bottom, centerX and width of the iconView
theTextButton.centerXAnchor.constraint(equalTo: centerXAnchor),
theTextButton.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1.0),
theTextButton.bottomAnchor.constraint(equalTo: bottomAnchor),
// constrain bottom of image button to top of text button
theImageButton.bottomAnchor.constraint(equalTo: theTextButton.topAnchor, constant: -4.0),
// set text button height to 20% of view height (instead of using intrinsic height)
theTextButton.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.2),
])
}
}
Теперь вы можете создавать каждыйпредставление одной строкой, например:
profileIconView = BottomTabBarView(withImageName: "earthIcon", labelText: "Profile", bkgColor: .blue)
И ваш класс контроллера представления становится намного проще / чище:
class BenViewController: UIViewController {
// Views to put in the StackView
var profileIconView = BottomTabBarView()
var actIconView = BottomTabBarView()
var achieveIconView = BottomTabBarView()
var growIconView = BottomTabBarView()
// 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
profileIconView = BottomTabBarView(withImageName: "earthIcon", labelText: "Profile", bkgColor: .blue)
actIconView = BottomTabBarView(withImageName: "actIcon", labelText: "Action", bkgColor: .brown)
achieveIconView = BottomTabBarView(withImageName: "achieveIcon", labelText: "Achieve", bkgColor: .red)
growIconView = BottomTabBarView(withImageName: "growIcon", labelText: "Grow", bkgColor: .purple)
// Add StackView
view.addSubview(stackView)
NSLayoutConstraint.activate([
// constrain stackView to bottom, leading and trailing (to safeArea)
stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
// Set height of the stackView (the bottom tab bar) as a proportion of the view height (7%).
stackView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.07),
])
}
}