0

I want to change the positions of my view programmatically at runtime using constraints I have following arrangement of views

 |
viewA
 |
viewB
 |
viewC

say i have viewA with topAnchor constraints set to top of margin of parent view and viewB with topAnchorset to viewA and so on for viewC

And i want to change the position of these views on certain action at runtime

 |
viewA
 |
viewC
 |
viewB

i have store two different constraints for viewB one with top of viewA and another with top of viewC

viewBTopConstraints = viewB.topAnchor.constraint(equalTo: viewA.bottomAnchor, constant: TOP_SPACE)

newViewBTopConstraints = viewB.topAnchor.constraint(equalTo: viewC.bottomAnchor, constant: TOP_SPACE)

In my toggle action method i have done something like this

viewBTopConstraints?.isActive = false
newViewBTopConstraints?.isActive = true

This works on first run of action however it fails on second time, on further debugging in view debugger i found out that it creates duplicate constraints rather that changing the original one.

2
  • You should only modify the isActive after the first time. Commented Nov 1, 2017 at 6:29
  • Is there a way to achieve this kind of behaviour? all i want is to toggle the position of these views based on certain action and since i have created my views programmatically using constraints, i am unable to figure out. Commented Nov 1, 2017 at 6:42

1 Answer 1

1

Your requirements sounds similar to an app where I have some constraints that change based on landscape or portrait. There I set up three groups of constraints:

  • Those that always are isActive = true
  • Those that are isActive = true in portrait
  • Those that are isActive = true in landscape

The trick is to put the latter two into arrays, and activate/deactive the proper array at the right time. Here's a snippet of what I mean:

var p = [NSLayoutConstraint]()
var l = [NSLayoutConstraint]()


////// portrait layout....

// pin info button above imageLayout, right justified

p.append(info.topAnchor.constraint(equalTo: margins.topAnchor, constant: 20.0))
p.append(info.trailingAnchor.constraint(equalTo: margins.trailingAnchor))


////// landscape layout....

// pin info button above buttons, right justified

l.append(info.topAnchor.constraint(equalTo: margins.topAnchor, constant: 20.0))
l.append(info.trailingAnchor.constraint(equalTo: margins.trailingAnchor))

Note that I'm not setting any isActive = true. I'm just appending things to the two arrays as needed. Now, in viewWillLayoutSubviews() - depending on your needs, viewDidLayoutSubviews() may be the better override - you *activate/deactivate the correct array:

NSLayoutConstraint.deactivate(l)
NSLayoutConstraint.deactivate(p)
if self.bounds.width > self.bounds.height {
    NSLayoutConstraint.activate(l)
} else {
    NSLayoutConstraint.activate(p)
}

I've found that working with individual constraints, setting isActive, greatly increases the risks of conflicts.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.