Updating Existing Constraints Does Not Work, Wrong Use of .Active Property

Modify constraint programmatically Swift

So this is the way I achieved this :

  • Create a constraint programmatically (height in my case) :

    // Drawing height property
    var drawingHeightConstraint: NSLayoutConstraint?
  • Deactivate old constraint and set the new one if needed

Note: heightContraints is an array of NSLayoutConstraint which contains my outlets

        for (index, (drawing, ratio)) in drawingElements.enumerate() {
drawingViews[index].image = UIImage(named: drawing)

// update height constraint if ratio is different than defaut ratio of 1/2
if ratio != 0.5 {
heightConstraints[index].active = false
drawingHeightConstraint = NSLayoutConstraint(item: drawingViews[index], attribute: .Height, relatedBy: .Equal, toItem: drawingView, attribute: .Height, multiplier: CGFloat(ratio), constant: 0)
drawingHeightConstraint!.active = true
}

}
  • Call layoutIfNeeded() right after (note: not sure when to call it)

How to update swift Layout Anchors?

Have you tried saving the relevant constraints you created using the layout anchors to properties, and then just changing the constant? E.g.

var ticketTop : NSLayoutConstraint?

func setup() {
ticketTop = ticketContainer.topAnchor.constraintEqualToAnchor(self.topAnchor, constant:100)
ticketTop.active = true
}

func update() {
ticketTop?.constant = 25
}

Possibly More Elegant

Depending on your taste for writing extensions, here is a possibly more elegant approach that doesn't use properties, but instead creates extension methods on NSLayoutAnchor and UIView to aid in more succinct usage.

First you would write an extension on NSLayoutAnchor like this:

extension NSLayoutAnchor {
func constraintEqualToAnchor(anchor: NSLayoutAnchor!, constant:CGFloat, identifier:String) -> NSLayoutConstraint! {
let constraint = self.constraintEqualToAnchor(anchor, constant:constant)
constraint.identifier = identifier
return constraint
}
}

This extension allows you to set an identifier on the constraint in the same method call that creates it from an anchor. Note that Apple documentation implies that XAxis anchors (left, right, leading, etc.) won't let you create a constraint with YAxis anchors (top, bottom, etc.), but I don't observe this to actually be true. If you did want that type of compiler checking, you would need to write separate extensions for NSLayoutXAxisAnchor, NSLayoutYAxisAnchor, and NSLayoutDimension (for width and height constraints) that enforce the same-axis anchor type requirement.

Next you would write an extension on UIView to get a constraint by identifier:

extension UIView {
func constraint(withIdentifier:String) -> NSLayoutConstraint? {
return self.constraints.filter{ $0.identifier == withIdentifier }.first
}
}

With these extensions in place, your code becomes:

func setup() {
ticketContainer.topAnchor.constraintEqualToAnchor(anchor: self.topAnchor, constant:100, identifier:"ticketTop").active = true
}

func update() {
self.constraint(withIdentifier:"ticketTop")?.constant = 25
}

Note that using constants or an enum instead of magic string names for the identifiers would be an improvement over the above, but I'm keeping this answer brief and focused.

How to change Auto Layout constraints after they are set when using constraintEqualToAnchor()?

You need to deactivate the previous constraint when activating a new one so that you don't end up over constraining your view. To do that, store a reference to each of the constraints as a property in your ViewController and then set the active property of the old constraint to false before creating and activating the new constraint:

Swift 2.x:

class ViewController: UIViewController {
var leftConstraint: NSLayoutConstraint?
var trailingConstraint: NSLayoutConstraint?
var topConstraint: NSLayoutConstraint?
var bottomConstraint: NSLayoutConstraint?

override func viewDidLoad() {
super.viewDidLoad()

let myView = UIView()
myView.backgroundColor = UIColor.orangeColor()
myView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myView)

leftConstraint = myView.leftAnchor.constraintEqualToAnchor(view.leftAnchor)
leftConstraint?.active = true

trailingConstraint = myView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor)
trailingConstraint?.active = true

topConstraint = myView.topAnchor.constraintEqualToAnchor(view.topAnchor)
topConstraint?.active = true

bottomConstraint = myView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor)
bottomConstraint?.active = true

/******************************************/
/* I try to change one of the constraints */
/******************************************/
leftConstraint?.active = false
leftConstraint = myView.leftAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -100)
leftConstraint?.active = true
}
}

Update for Swift 3 syntax:

class ViewController: UIViewController {
var leftConstraint: NSLayoutConstraint?
var trailingConstraint: NSLayoutConstraint?
var topConstraint: NSLayoutConstraint?
var bottomConstraint: NSLayoutConstraint?

override func viewDidLoad() {
super.viewDidLoad()

let myView = UIView()
myView.backgroundColor = UIColor.orange
myView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myView)

leftConstraint = myView.leftAnchor.constraint(equalTo: view.leftAnchor)
leftConstraint?.isActive = true

trailingConstraint = myView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
trailingConstraint?.isActive = true

topConstraint = myView.topAnchor.constraint(equalTo: view.topAnchor)
topConstraint?.isActive = true

bottomConstraint = myView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
bottomConstraint?.isActive = true

/******************************************/
/* I try to change one of the constraints */
/******************************************/
leftConstraint?.isActive = false
leftConstraint = myView.leftAnchor.constraint(equalTo: view.rightAnchor, constant: -100)
leftConstraint?.isActive = true
}
}

AutoLayout - space views apart a preferred distance and decrease down to a minimum distance before scrolling

Start simple -- and think about it in terms of "what I want to do" before you think about the code.

So, suppose we have:

  • scroll view with a Width of 360
  • item views with widths of 44
  • MAX (preferred) spacing of 80
  • MIN spacing of 40

When you add/remove items:

  • Multiply number of items x 40
  • Subtract that from 360 (scroll view width) to get the "available space"
  • Divide available space by numItems-1 to get the space between items
  • space = MIN(space, 80)
  • space = MAX(space, 40)

So it looks like this (the gray rectangle is the scroll view frame):

Sample Image

You can then use a horizontal stack view and update the .spacing property, or update the Leading/Trailing constraints between the items.

If using a stack view, the stack view's Trailing constraint should equal the scroll view's ContentLayoutGuide Trailing, and scrolling is automatic.

If using constraints between items, the last item should get Trailing equal to scroll view's ContentLayoutGuide Trailing, and again scrolling is automatic.

Stack view is much easier, but which method to use depends on how you want to display adding / removing items. If you want to animate them into place, you probably don't want to use a stack view.


Edit - examples...

Here are two examples: ScrollingShelfA uses subviews with Leading/Trailing constraints; ScrollingShelfB uses a stack view.

ScrollingShelfA.h

#import <UIKit/UIKit.h>

@interface ScrollingShelfA : UIScrollView

@property (assign, nonatomic) CGSize itemSize;

@property (assign, nonatomic) CGFloat preferredInteritemSpacing;
@property (assign, nonatomic) CGFloat minimumInteritemSpacing;

- (void)addView:(UIView *)view;
- (void)removeLastView;

@end

ScrollingShelfA.m

#import "ScrollingShelfA.h"

@interface ScrollingShelfA ()

@property (strong, nonatomic) UIView *framingView;

@property (strong, nonatomic, readwrite) NSMutableArray<__kindof UIView *> *mutableArrangedSubviews;

@end

@implementation ScrollingShelfA

- (instancetype)init {
return [self initWithFrame:CGRectZero];
}

- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self initialize];
}
return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self initialize];
}
return self;
}

- (void)initialize {
self.mutableArrangedSubviews = [[NSMutableArray alloc] init];

self.framingView = [UIView new];
self.framingView.backgroundColor = [UIColor orangeColor];
self.framingView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:self.framingView];

[NSLayoutConstraint activateConstraints:@[

[self.framingView.leadingAnchor constraintEqualToAnchor:self.contentLayoutGuide.leadingAnchor],
[self.framingView.topAnchor constraintEqualToAnchor:self.contentLayoutGuide.topAnchor],
[self.framingView.trailingAnchor constraintEqualToAnchor:self.contentLayoutGuide.trailingAnchor],
[self.framingView.bottomAnchor constraintEqualToAnchor:self.contentLayoutGuide.bottomAnchor],

[self.framingView.heightAnchor constraintEqualToAnchor:self.frameLayoutGuide.heightAnchor],

]];

//apply this last because it requires some changes to the constraints of the views involved.
self.itemSize = CGSizeMake(44, 44);

self.preferredInteritemSpacing = 80.0;
self.minimumInteritemSpacing = 20.0;

}

- (void)updateHorizontalPositions {
if (self.mutableArrangedSubviews.count == 0) {
// no items, so we don't have to do anything
return;
}

//clear the existing Leading / Trailing constraints
for (NSLayoutConstraint *constraint in self.framingView.constraints) {
if (constraint.firstAttribute == NSLayoutAttributeLeading || constraint.firstAttribute == NSLayoutAttributeTrailing) {
constraint.active = NO;
}
}

//the first item will be equal to the positionView's leading
UIView *currentItem = [self.mutableArrangedSubviews firstObject];
[NSLayoutConstraint activateConstraints:@[
[currentItem.leadingAnchor constraintEqualToAnchor:self.framingView.leadingAnchor]
]];

// spacing for remaining items

CGFloat nViews = self.mutableArrangedSubviews.count;
CGFloat availableSpace = self.frame.size.width - (nViews * self.itemSize.width);
CGFloat spacing = availableSpace / (nViews - 1);

spacing = MIN(spacing, self.preferredInteritemSpacing);
spacing = MAX(spacing, self.minimumInteritemSpacing);

UIView *previousItem;
for (int x = 1; x < self.mutableArrangedSubviews.count; x++) {
previousItem = currentItem;
currentItem = self.mutableArrangedSubviews[x];
[currentItem.leadingAnchor constraintEqualToAnchor:previousItem.trailingAnchor constant:spacing].active = YES;
}

[currentItem.trailingAnchor constraintEqualToAnchor:self.framingView.trailingAnchor].active = YES;

}

- (void)addView:(UIView *)view {

if (CGSizeEqualToSize(self.itemSize, CGSizeZero)) {
self.itemSize = view.bounds.size;
} else {
[NSLayoutConstraint activateConstraints:@[
[view.widthAnchor constraintEqualToConstant:self.itemSize.width],
[view.heightAnchor constraintEqualToConstant:self.itemSize.height]
]];
}

CGFloat height = MAX(self.itemSize.height, self.itemSize.width);

view.layer.cornerRadius = height / 2.0;
view.layer.masksToBounds = YES;
view.clipsToBounds = YES;

view.translatesAutoresizingMaskIntoConstraints = NO;

[self.mutableArrangedSubviews addObject:view];

view.translatesAutoresizingMaskIntoConstraints = NO;

[self.framingView addSubview:view];

[self.framingView sendSubviewToBack:view];

[view.centerYAnchor constraintEqualToAnchor:self.framingView.centerYAnchor].active = YES;

[self updateHorizontalPositions];

// animate into view if necessary
dispatch_async(dispatch_get_main_queue(), ^{
CGRect r = CGRectMake(self.contentSize.width - 1.0, 0.0, 1.0, 1.0);
[self scrollRectToVisible:r animated:YES];
});

}

- (void)removeLastView {
[self.mutableArrangedSubviews removeLastObject];
[self updateHorizontalPositions];
}

- (void)layoutSubviews {
[super layoutSubviews];
[self updateHorizontalPositions];
}

@end

ScrollingShelfB.h

#import <UIKit/UIKit.h>

@interface ScrollingShelfB : UIScrollView

@property (assign, nonatomic) CGSize itemSize;

@property (assign, nonatomic) CGFloat preferredInteritemSpacing;
@property (assign, nonatomic) CGFloat minimumInteritemSpacing;

- (void)addView:(UIView *)view;
- (void)removeLastView;

@end

ScrollingShelfB.m

#import "ScrollingShelfB.h"

@interface ScrollingShelfB ()

@property (strong, nonatomic) UIStackView *framingStackView;

@end

@implementation ScrollingShelfB

- (instancetype)init {
return [self initWithFrame:CGRectZero];
}

- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self initialize];
}
return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self initialize];
}
return self;
}

- (void)initialize {
NSLog(@"init");

self.framingStackView = [UIStackView new];
self.framingStackView.alignment = UIStackViewAlignmentCenter;
self.framingStackView.backgroundColor = [UIColor cyanColor];
self.framingStackView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:self.framingStackView];

[NSLayoutConstraint activateConstraints:@[

[self.framingStackView.leadingAnchor constraintEqualToAnchor:self.contentLayoutGuide.leadingAnchor],
[self.framingStackView.topAnchor constraintEqualToAnchor:self.contentLayoutGuide.topAnchor],
[self.framingStackView.trailingAnchor constraintEqualToAnchor:self.contentLayoutGuide.trailingAnchor],
[self.framingStackView.bottomAnchor constraintEqualToAnchor:self.contentLayoutGuide.bottomAnchor],

[self.framingStackView.heightAnchor constraintEqualToAnchor:self.frameLayoutGuide.heightAnchor],

]];

//apply this last because it requires some changes to the constraints of the views involved.
self.itemSize = CGSizeMake(44, 44);

self.preferredInteritemSpacing = 80.0;
self.minimumInteritemSpacing = 20.0;

}

- (void)updateHorizontalPositions {
if (self.framingStackView.arrangedSubviews.count == 0) {
// no items, so we don't have to do anything
return;
}

// spacing for stack view

CGFloat nViews = self.framingStackView.arrangedSubviews.count;
CGFloat availableSpace = self.frame.size.width - (nViews * self.itemSize.width);
CGFloat spacing = availableSpace / (nViews - 1);

spacing = MIN(spacing, self.preferredInteritemSpacing);
spacing = MAX(spacing, self.minimumInteritemSpacing);

self.framingStackView.spacing = spacing;
}

- (void)addView:(UIView *)view {

if (CGSizeEqualToSize(self.itemSize, CGSizeZero)) {
self.itemSize = view.bounds.size;
} else {
[NSLayoutConstraint activateConstraints:@[
[view.widthAnchor constraintEqualToConstant:self.itemSize.width],
[view.heightAnchor constraintEqualToConstant:self.itemSize.height]
]];
}

CGFloat height = MAX(self.itemSize.height, self.itemSize.width);

view.layer.cornerRadius = height / 2.0;
view.layer.masksToBounds = YES;
view.clipsToBounds = YES;

[self.framingStackView addArrangedSubview:view];

[self updateHorizontalPositions];

// animate into view if necessary
dispatch_async(dispatch_get_main_queue(), ^{
CGRect r = CGRectMake(self.contentSize.width - 1.0, 0.0, 1.0, 1.0);
[self scrollRectToVisible:r animated:YES];
});

}

- (void)removeLastView {
[self.framingStackView.arrangedSubviews.lastObject removeFromSuperview];
[self updateHorizontalPositions];
}
@end

and an example view controller that adds an instance of each, with Add View / Remove View buttons:

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
@end

ViewController.m

#import "ViewController.h"
#import "ScrollingShelfA.h"
#import "ScrollingShelfB.h"

@interface ViewController ()
{
ScrollingShelfA *scShelf;
ScrollingShelfA *stShelf;
ScrollingShelfB *ssShelf;
NSArray <UIColor *>*colors;
NSInteger idx;
}
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

scShelf = [ScrollingShelfA new];
scShelf.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0];

// no overlap on first example
scShelf.minimumInteritemSpacing = 20.0;

stShelf = [ScrollingShelfA new];
stShelf.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0];

// allow overlap on second example
stShelf.minimumInteritemSpacing = -22.0;

ssShelf = [ScrollingShelfB new];
ssShelf.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0];

ssShelf.minimumInteritemSpacing = 20.0;

UIFont *fnt = [UIFont systemFontOfSize:14.0 weight:UIFontWeightLight];

UILabel *labelA = [UILabel new];
labelA.text = @"Subviews with Constraints - min spacing: 20";
labelA.font = fnt;

UILabel *labelB = [UILabel new];
labelB.text = @"Constraints with Overlap - min spacing: -22";
labelB.font = fnt;

UILabel *labelC = [UILabel new];
labelC.text = @"Using Stack View";
labelC.font = fnt;

for (UIView *v in @[labelA, scShelf, labelB, stShelf, labelC, ssShelf]) {
v.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:v];
}

// respect safeArea
UILayoutGuide *g = self.view.safeAreaLayoutGuide;

[NSLayoutConstraint activateConstraints:@[

[labelA.topAnchor constraintEqualToAnchor:g.topAnchor constant:40.0],
[labelA.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:20.0],

[scShelf.topAnchor constraintEqualToAnchor:labelA.bottomAnchor constant:4.0],
[scShelf.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:20.0],
[scShelf.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-20.0],
[scShelf.heightAnchor constraintEqualToConstant:60.0],

[labelB.topAnchor constraintEqualToAnchor:scShelf.bottomAnchor constant:40.0],
[labelB.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:20.0],

[stShelf.topAnchor constraintEqualToAnchor:labelB.bottomAnchor constant:4.0],
[stShelf.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:20.0],
[stShelf.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-20.0],
[stShelf.heightAnchor constraintEqualToConstant:60.0],

[labelC.topAnchor constraintEqualToAnchor:stShelf.bottomAnchor constant:40.0],
[labelC.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:20.0],

[ssShelf.topAnchor constraintEqualToAnchor:labelC.bottomAnchor constant:4.0],
[ssShelf.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:20.0],
[ssShelf.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-20.0],
[ssShelf.heightAnchor constraintEqualToConstant:60.0],

]];

// let's add AddView and RemoveView buttons
UIButton *addBtn = [UIButton new];
[addBtn setTitle:@"Add View" forState:UIControlStateNormal];
[addBtn setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
[addBtn setTitleColor:UIColor.lightGrayColor forState:UIControlStateHighlighted];
addBtn.backgroundColor = UIColor.systemRedColor;
addBtn.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:addBtn];

UIButton *removeBtn = [UIButton new];
[removeBtn setTitle:@"Remove View" forState:UIControlStateNormal];
[removeBtn setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
[removeBtn setTitleColor:UIColor.lightGrayColor forState:UIControlStateHighlighted];
removeBtn.backgroundColor = UIColor.systemRedColor;
removeBtn.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:removeBtn];

[NSLayoutConstraint activateConstraints:@[

[addBtn.topAnchor constraintEqualToAnchor:ssShelf.bottomAnchor constant:40.0],
[addBtn.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:40.0],
[addBtn.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-40.0],

[removeBtn.topAnchor constraintEqualToAnchor:addBtn.bottomAnchor constant:20.0],
[removeBtn.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:40.0],
[removeBtn.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-40.0],

]];

[addBtn addTarget:self action:@selector(addView) forControlEvents:UIControlEventTouchUpInside];
[removeBtn addTarget:self action:@selector(removeView) forControlEvents:UIControlEventTouchUpInside];

colors = @[
UIColor.redColor, UIColor.blueColor, UIColor.greenColor, UIColor.yellowColor,
UIColor.systemRedColor, UIColor.systemBlueColor, UIColor.systemGreenColor, UIColor.systemYellowColor,
];

idx = -1;

}
- (void)addView {
idx++;
UIView *v = [UIView new];
v.backgroundColor = colors[idx % colors.count];
[scShelf addView:v];
v = [UIView new];
v.backgroundColor = colors[idx % colors.count];
[stShelf addView:v];
v = [UIView new];
v.backgroundColor = colors[idx % colors.count];
[ssShelf addView:v];
}
- (void)removeView {
if (idx > 0) {
[scShelf removeLastView];
[stShelf removeLastView];
[ssShelf removeLastView];
idx--;
}
}

@end

Edit 2

If you want to allow overlap to a maximum distance, you can use the "Subviews with Constraints" approach and set a minimumInteritemSpacing to a negative value (such as 1/2 the width of an item).

Since you'll probably also want the items to overlap left-to-right, send the new item view to the back in addView:

[self.framingView addSubview:view];

// add this line
[self.framingView sendSubviewToBack:view];

[view.centerYAnchor constraintEqualToAnchor:self.framingView.centerYAnchor].active = YES;

Nothing else would need to change in ScrollingShelfA

Edit 3

I updated the code above, adding the "send to back" line and adding a 2nd instance of ScrollingShelfA with a min spacing of -22. Also implemented layoutSubviews to auto-update the positions when the frame changes (such as on device rotation).

Looks like this:

Sample Image

Sample Image

Sample Image

All three examples use .contentLayoutGuide constraints to "auto-enable" scrolling as needed.

AutoLayout animate sliding view out and sliding other views over to take its place

I'm not an Apple engineer, so I don't know the ins-and-outs of this, but I've seen it often enough.

As a general rule ... when animating constraints we want to allow auto-layout to manage the view hierarchy from a "top down" standpoint.

If you change constraints and tell a subview to layoutIfNeeded, it appears that the superview either isn't made aware of what's going on, or the timing causes issues.

If you change your animation block to [weakSelf.superview layoutIfNeeded]; that should fix the "jumping" problem:

    __weak MyShelf *weakSelf = self;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionAllowAnimatedContent|UIViewAnimationOptionAllowUserInteraction
animations:^{
view.alpha = 0.0;
view.center = CGPointMake(-weakSelf.itemSize.width, view.center.y);
[weakSelf updateHorizontalPositions];

// tell the superview to initiate auto-layout updates
//[weakSelf layoutIfNeeded];
[weakSelf.superview layoutIfNeeded];

} completion:^(BOOL finished){
[view removeFromSuperview];
//only reorder the views vertically if the one being removed was the top-most view
if (wasInFront) {
[weakSelf updateVerticalPositions];
}
}];

How to collapse a view in Xamarin.iOS in runtime?

I got the answer from Xamarin forum, and the fact is, by setting the ...Anchor property, you are adding a constraint, not modifying it, even if you write the same line with .Active = false.
That explains why the layout changed for the first time, but not afterwards.

You need to cycle through the constraints to remove one:

foreach (NSLayoutConstraint constraint in FilterLayout.Constraints)
{
if (constraint.FirstAttribute == NSLayoutAttribute.Height)
{
FilterLayout.RemoveConstraint(constraint);
}
}

Calling layoutIfNeeded does not affect this behaviour, but using StackView could be an alternative solution.

How can I change constraints priority in run time

As stated in NSLayoutConstraint class reference:

Priorities may not change from nonrequired to required, or from required to nonrequired. An exception will be thrown if a priority of NSLayoutPriorityRequired in OS X or UILayoutPriorityRequired in iOS is changed to a lower priority, or if a lower priority is changed to a required priority after the constraints is added to a view. Changing from one optional priority to another optional priority is allowed even after the constraint is installed on a view.

Use priority 999 instead of 1000. It won't be absolutely required technically speaking, but it'll be a higher priority than anything else.



Related Topics



Leave a reply



Submit