I have a mini game in my project where you have to guess a flag of a country, I don't use Interface Builder, all UI is written in code. When user taps one of the flags I load new set of countries to guess, set their flags to buttons and since flags are different in sizes from previous ones I need to adjust UIButton constraints so I call my function setupConstraints() which looks like that:
func setupConstraints() {
NSLayoutConstraint.activate([
countryNameLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10),
countryNameLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
countryNameLabel.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -20),
countryNameLabel.heightAnchor.constraint(equalToConstant: 30),
firstCountryButton.topAnchor.constraint(equalTo: countryNameLabel.bottomAnchor, constant: 35),
firstCountryButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
firstCountryButton.heightAnchor.constraint(equalToConstant: 120),
firstCountryButton.widthAnchor.constraint(equalTo: firstCountryButton.heightAnchor, multiplier: flagImages[0].getAspectRatio()),
secondCountryButton.topAnchor.constraint(equalTo: firstCountryButton.bottomAnchor, constant: 25),
secondCountryButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
secondCountryButton.heightAnchor.constraint(equalToConstant: 120),
secondCountryButton.widthAnchor.constraint(equalTo: secondCountryButton.heightAnchor, multiplier: flagImages[1].getAspectRatio()),
thirdCountryButton.topAnchor.constraint(equalTo: secondCountryButton.bottomAnchor, constant: 25),
thirdCountryButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
thirdCountryButton.heightAnchor.constraint(equalToConstant: 120),
thirdCountryButton.widthAnchor.constraint(equalTo: thirdCountryButton.heightAnchor, multiplier: flagImages[2].getAspectRatio()),
])
}
This function works fine when I initially setup my View Controller but when I call it to update constraints I get in log following:
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x280d92940 UIButton:0x102315180.height == 120 (active)>",
"<NSLayoutConstraint:0x280d92990 UIButton:0x102315180.width == 1.5*UIButton:0x102315180.height (active)>",
"<NSLayoutConstraint:0x280db2b70 UIButton:0x102315180.width == 2*UIButton:0x102315180.height (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x280db2b70 UIButton:0x102315180.width == 2*UIButton:0x102315180.height (active)>
I see that it's trying to set width twice but I don't know why. I'm not even sure if my approach to call this function every time to setup constraints is the right one.
Here's one way to handle it:
Create a struct ButtonSizeConstraints:
struct ButtonSizeConstraints {
let widthConStraint: NSLayoutConstraint
let heightConstraint: NSLayoutConstraint
}
Give your view an array of ButtonSizeConstraints
, once for each button. (You could also have separate variables firstButtonSizeConstraints
, secondButtonSizeConstraints
, etc, but by making it an array you can loop through it.)
In your setupConstraints
function, put those constraints into local vars, add them to your array of ButtonSizeConstraints
, and activate them outside of the code you posted.
Then, when you load a new image into one or more of your buttons, fetch that button's ButtonSizeConstraints
, update that constraint's constant value, and call the parent view's layoutIfNeeded()
method.