10

I have this simple view:

- (void)viewDidLoad
{
    [super viewDidLoad];
    redBox = [[UIView alloc] init];
    [redBox setBackgroundColor:[UIColor redColor]];
    [redBox setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:redBox];

    //H:
    widthConstraint = [NSLayoutConstraint constraintWithItem:redBox
                                                   attribute:NSLayoutAttributeWidth
                                                   relatedBy:NSLayoutRelationEqual
                                                      toItem:self.view
                                                   attribute:NSLayoutAttributeWidth
                                                  multiplier:0.5
                                                    constant:0.0];
    [self.view addConstraint:widthConstraint];

    //More constraints... 
}

I’d like to animate an increase in redBox's width.

I’ve tried this:

widthConstraint.constant = 100;

[UIView animateWithDuration:1
                 animations:^{
                     [self.view layoutIfNeeded];
                 }
 ];

this increases the view’s width by 100 and animates it, but I need to increase it by an amount proportional to its superview’s width. In other words, I’d like to set widthConstraint’s multiplier to 0.8.

But NSLayoutConstraint’s multiplier is readonly! Does this mean I have to remove, modify and re-add widthConstraint every time I want to animate a change to its multiplier or is there a better way?

Eric
  • 16,003
  • 15
  • 87
  • 139

2 Answers2

7

Unfortunately, there is no better way. Removing and re-adding with a different multiplier is your only option. Please file a bug that you would like to see multiplier to be readwrite.

Scott Berrevoets
  • 16,921
  • 6
  • 59
  • 80
  • 1
    There is a good reason it's readonly; changing it is expensive and requires recomputation of the layout; changing the constant, on the other hand, is cheap. So, if you can, for example, just compute the correct constant and change it, it's much faster. The readonly is there to encourage this. – Jesse Rusak Dec 11 '13 at 15:48
  • 9
    Dynamically recomputing layout changes at runtime, isn't that what Auto Layout is precisely for? – Eric Dec 11 '13 at 15:52
  • 1
    @Eric - see http://floriankugler.com/blog/2013/4/21/auto-layout-performance-on-ios - the performance cost increases exponentially with the number of requirements. You can use Auto Layout to recompute layout changes at runtime (by replacing the constraint entirely), but the API is written to encourage you to take a performant approach. – Aaron Brager Dec 11 '13 at 16:35
  • @AaronBrager: That post's methodology was misguided, see here: http://pilky.me/view/36 – Eric Dec 12 '13 at 14:30
  • 1
    Odd indeed. I thought it would be quite clean to hide/show an element by just changing a multiplier from 0 to 1, and not have the code touch any value related to an actual offset. I now do `constraint.constant = constraint.firstItem.frame.size.height * {0,1}` to achieve the same. – mvds Apr 30 '15 at 11:15
2

I asked this question before. And we are found only one way, it's remove constraints and added it later with modify multipler. @"It's Apple baby"(©My Boss)

UPD

look at Masonry mb you can replace multipler on plain constrain with constant.

Community
  • 1
  • 1
Bimawa
  • 3,535
  • 2
  • 25
  • 45