2

I had this problem in various different settings, both with IB and when defining constraints manually. Here is the current setting:

I have a label and a text field in a container view using the following visual format constraints:

H:|-(4)-[label(labelWidth)]-(4)-[editor]-(4)-|
option = NSLayoutFormatAlignAllFirstBaseline

V:|-(4)-[editor]-(4)-|

For these constraints, the label is positioned outside the container view in the top-left corner of the screen (actually under the navigation bar).

When I add these constraints:

V:|-(>=4)-[label]-(>=4)-|

the label is positioned 4pt from the top (matching the new constraint).

In both cases, once I tap into the text field opening the keyboard and then closing it again (no change is needed for this to happen), the label correctly aligns with the text fields baseline.

[EDIT: Added some screenshots] Initial state:

Initial state

Keyboard opened:

Keyboard opened

Correct display after keyboard closed:

After closing the keyboard

In the Xcode debugger, the baseline constraint shows as inactive before and as active after the keyboard was opened and closed.

It seems as if the baseline of the textfield is not (correctly) computed until after the first edit. Initializing the textfield with nil, @"" or some text does not affect the behavior.

The question is, what's causing this behavior and more importantly, what can I do about it?

Michael
  • 250
  • 3
  • 8
  • I am having this issue too, the accepted answer below didn't helped – speeder May 25 '16 at 18:01
  • @speeder: I don't remember the details anymore, just that the key for this workaround was when to call setNeedsUpdateContraints. But that workaround seems to be rather fragile anyway – Michael May 26 '16 at 20:53
  • I ended just slapping lots of "top-top" and "bottom-bottom" constraints, PLUS the baseline constraint... Still, very "WTF-worthy" from apple's part. – speeder May 27 '16 at 15:58
  • @speeder Just a wild guess: At another occasion I found out that text fields have an invisible height = 30pt constraint. Maybe that's related to our problem in that this constraint is interfering (added too late, f.e.) with other (the baseline) constraints. That would explain why your top-top/bottom-bottom constraints help solve this problem (also why my workaround works). – Michael May 28 '16 at 09:19
  • @speeder Can you try if adding an explicit Height=30pt constraint to you text field also solves the problem? – Michael May 28 '16 at 09:20
  • That was necessary anyway. I am using scrollviews of unknown size (due to autolayout and unknown amount of data), I am resizing them by adding a constraint between scrollview bottom edge and my "done" button, I had a problem where sometimes autolayout would decide the best solution for my constraints was make random textfields or labels to become 300 pixels tall, and make the scrollview giant. So I added Height=30pt to everything. – speeder May 29 '16 at 13:51

1 Answers1

1

If the text field is created programmatically, or if the baseline alignment constraint is not added by IB, then the text fields baseline view is not correctly positioned.

A call to [textField setNeedsUpdateConstraints] at the right time (see below) fixes this.

In my case I have a custom container view, which adds/replaces constraints to layout the label an text field. I had to call [textField setNeedsUpdateConstraints] in the layoutSubviews method of the container view. Calling it in updateConstraints where the constraints are modified did not help.

In a similar scenario where the text field already had a baseline alignment (with any view, the label or another one) which would be replaced by a new baseline alignment, the problem does not occur, apparently because IB would somehow take care to layout the participating text field in time.

So my workaround/solution is:

- (void)updateConstraints {
  // setup constraints for affected views in self.viewsDictionary
  [super updateConstraints];
}

- (void)layoutSubviews {
  [super layoutSubviews];
  for (UIView* view in self.viewDictionary.objectEnumerator) {
    [view setNeedsUpdateConstraints];
  }
}
Michael
  • 250
  • 3
  • 8