Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autolayout in UITextField: Auto Layout still required after executing -layoutSubviews

I'm subclassing UITextField to add a label on the left side. I'm using autolayout to layout the label. However, I keep getting this crash:

Here's how I am doing my layout code:

- (void)updateConstraints {

self.segmentLabel.translatesAutoresizingMaskIntoConstraints = NO;

NSLayoutConstraint *constraint;
constraint = [NSLayoutConstraint constraintWithItem:self.segmentLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0f];
[self addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.segmentLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0f];
[self addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.segmentLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0f];
[self addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.segmentLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:self.segmentWidth];
[self addConstraint:constraint];

[super updateConstraints];

}

When I don't make any adjustments to the textfield, this works fine.

However, if I try to set the placeholder text, I get this exception:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. DDSegmentedTextField's implementation of -layoutSubviews needs to call super.'

However, I'm not overriding -layoutSubviews.

Has anyone encountered this? What am I doing wrong?

Thanks!

like image 271
Sean Danzeiser Avatar asked Aug 29 '14 18:08

Sean Danzeiser


2 Answers

So I ran into this same error a few days ago as well. It turns out I was trying to layout subviews inside my UITextfield subclass, setting properties on them, moving them, etc, but was never explicitly telling the view to lay itself out (i.e. calling [self layoutIfNeeded]).

iOS 8 seems to force to a view to layout all its subviews, and then configures constraints on it. iOS 7 won't, and needs you to explicitly tell views to redraw their subviews when you change if you're using autolayout.

In my case, I had subclassed UITextField and added a label to the side. I configured the frame of the label by adding constraints to the UITextfield. One of the public methods I could call on my class was

- (void)setLabelText:(NSString *)newText{
    self.sideLabel.text = newText;
}

This caused my application to crash when a view controller appeared containing my subclassed textfield. By adding layoutIfNeeded everything now works fine in iOS7 and iOS8.

- (void)setLabelText:(NSString *)newText{
    self.sideLabel.text = newText;
    [self layoutIfNeeded];
}

This needs to be called every time you change a part of the view in your subclass. This includes the setup when you add subviews, when you change view properties, anything really. Before the function that's changing your view returns, call layoutIfNeeded on your view. This seems to apply for a few standard UI controls including UITextfield, UITableView and UICollectionView, though I'm sure there are others. I hope this was clear enough and helped solve your problem.

The error you're getting isn't super useful, and didn't even apply in my case. Though I was receiving the exact same error, none of my views implementing layoutSubviews, and thus were all using the [super layoutSubviews] method.

like image 180
Pat Butkiewicz Avatar answered Oct 10 '22 03:10

Pat Butkiewicz


This problem shows up in iOS < 8

While creating the UIView subclass and adding views, we can instruct the control to construct and autolayout first the subviews. Use this statement when the UI needs to be updated:

[self layoutIfNeeded];

iOS 8+ are handling the issue quite on there own internally.

like image 24
Shanu ji Avatar answered Oct 10 '22 03:10

Shanu ji