Setting constraints programmatically

Based upon a review of your code, a few comments:

  1. You generally don’t need to adjust constraints when a view appears. If you find yourself doing this, it often means that you haven’t configured your storyboard correctly (or at least, not efficiently). The only time you really need to set/create constraints is either (a) you’re adding views programmatically (which I’m suggesting is more work than it’s worth); or (b) you need to do some runtime adjustment of constraints (see third bullet under point 3, below).

  2. I don’t mean to belabor it, but your project had a bunch of redundant code. E.g.

    • You were setting the frame for the scroll view, but that is governed by constraints, so that does nothing (i.e. when the constraints are applied, any manually set frame settings will be replaced). In general, in auto layout, don’t try changing frame directly: Edit the constraints. But, no changing of constraints is needed at all anyway, so the point is moot.

    • You were setting the content size for the scroll view, but in auto layout, that, too, is governed by constraints (of the subviews), so that was unnecessary.

    • You were setting constraints for the scrollview (which were already zero), but then you weren’t adding the view from the NIB into the scrollview, defeating any intent there, too. The original question was how to change the bottom constraint of the scroll view. But the bottom constraint for that is already zero, so I see no reason to set it to zero again.

  3. I’d suggest a more radical simplification of your project:

    • You’re making life much harder on yourself by storing your views in NIBs. It’s much easier if you stay within the the storyboard world. We can help you do the NIB stuff if you really need to, but why make life so hard on yourself?

    • Use cell prototypes to facilitate the design of the cells in your table. You can also define the segues to go from the cells to the next scene. This eliminates any need to write any didSelectRowAtIndexPath or prepareForSegue code. Clearly, if you have something you need to pass to the next scene, by all means use prepareForSegue, but nothing you’ve presented thus far requires that, so I’ve commented it out in my examples.

    • Assuming you were looking for a practical example of programmatically changing constraints, I’ve set up the scene so that the text view will change its height programmatically, based upon the text in the text view. As always, rather than iterating through the constraints to find the one in question, when altering an existing constraint that IB created for me, I think it’s far more efficient to set up an IBOutlet for the constraint, and edit the constant property for the constraint directly, so that’s what I’ve done. So I set up the view controller to be the delegate of the text view, and wrote a textViewDidChange that updated the text view’s height constraint:

      #pragma mark - UITextViewDelegate
      
      - (void)textViewDidChange:(UITextView *)textView
      {
          self.textViewHeightConstraint.constant = textView.contentSize.height;
          [self.scrollView layoutIfNeeded];
      }
      

      Note, my text view has two height constraints, a mandatory minimum height constraint, and a medium priority constraint that I change above based upon the amount of text. The main point is that it illustrates a practical example of changing constraints programmatically. You shouldn’t have to muck around with the scrollview’s bottom constraint at all, but this is shows a real-world example of when you might want to adjust a constraint.


When you add a scrollview in IB, it will automatically get all the constraints you need. You probably don’t want to be adding a constraint programmatically (at least not without removing the existing bottom constraint).

Two approaches might be simpler:

  1. Create an IBOutlet for your existing bottom constraint, say scrollViewBottomConstraint. Then you can just do

    self.scrollViewBottomConstraint.constant = 0.0;
    
  2. Or create your view initially in IB where the bottom constraint is 0.0 and then you don’t have to do anything programmatically at all. If you want to layout a long scrollview and it’s subviews, select the controller, set it’s simulated metrics from “inferred” to “free form”. Then you can change the size of the view, set the scrollview’s top and bottom constraints to be zero, layout everything you want inside the scroll view, and then when the view is presented at runtime, the view will be resized appropriately, and because you’ve defined the scrollview’s top and bottom constraints to be 0.0, it will be resized properly. It looks a bit odd in IB, but it works like a charm when the app runs.

  3. If you’re determined to add a new constraint, you could either programmatically remove the old bottom constraint, or set the old bottom constraints’ priority down as low as possible, and that way your new constraint (with higher priority) will take precedence, and the old, low-priority bottom constraint will gracefully not be applied.

But you definitely don’t want to just add a new constraint.

Leave a Comment