0
votes

I have a subclassed UIView that creates a UILabel programmatically but it does not do well when the UIView is given constraints...

What I am trying to do:

enter image description here

The label should be positioned on top of the view.

My subclassed UIView will creates a UILabel like this:

//In interface
@property(nonatomic, strong) UILabel *myLabel;

//in implementation
self.myLabel = [[UILabel alloc] initWithFrame:[self bounds]];
/*
set properties
*/
[self.superview addSubview:[self myLabel]];

This provides the desired behavior with the label having the same size and position as the subclassed UIView. But when I add constraints to the UIView in the storyboard, the UILabel is rendered in the wrong place.

Here's what's happening: (UIView shaded yellow, UILabel shaded teal) enter image description here

I have tried changing

[self.superview addSubview:[self myLabel]];

to

[self addSubview:[self myLabel]];

but that does not work either.

How can I make the UILabel render on top of the UIView?

2
I had a similar issue and had to move to programmatic constraints not IB-based ones to resolve it. - Cocoadelica
Is your positioning of the label in the init method or an override of layoutSubviews? It should be in the latter. - Andrew Monshizadeh
Currently, I am calling a setup method from init. This is where I am handling the label. If I put it inside layoutSubviews, it seems that it creates a new label every time the UIView is updated. Not sure how to add the view in init so it only adds one then setting the position in layoutSubviews since the label is getting an alloc initWithFrame... - BBruce

2 Answers

0
votes

If you add the label in code, you should also add constraints to it in code. The trick with constraints is to remember to add the constraint to the ( hierarchically )topmost view of the 2 views linked by the constraint, or to the first common parent view.

Note that mixing IB auto layout and coded constraints might be quite the headache. I've ran into cases where I've had to set UIView.translatesAutoResizingMasksIntoConstraints to NO for it to work properly.

0
votes

I just tried this after adding the UILabel to the UIView:

NSLayoutConstraint *xPosConstraint = [NSLayoutConstraint constraintWithItem:self
                                                                  attribute:NSLayoutAttributeCenterX
                                                                  relatedBy:NSLayoutRelationEqual
                                                                     toItem:self.myLabel
                                                                  attribute:NSLayoutAttributeCenterX
                                                                 multiplier:1.0
                                                                   constant:0];

[self addConstraint:xPosConstraint];

Which caused a crash...

The view hierarchy is not prepared for the constraint: 
<NSLayoutConstraint:0x7fe0f0f750d0 MyUIView:0x7fe0f0f55b90.centerX == UILabel:0x7fe0f0f71810.centerX>
When added to a view, the constraint's items must be descendants of that view 
(or the view itself). This will crash if the constraint needs to be resolved before 
the view hierarchy is assembled. 
Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2014-12-24 13:26:40.319 circle[28901:2153934] View hierarchy unprepared for constraint.
Constraint: <NSLayoutConstraint:0x7fe0f0f750d0 MyUIView:0x7fe0f0f55b90.centerX == UILabel:0x7fe0f0f71810'0%'.centerX>
Container hierarchy: < MyUIView: 0x7fe0f0f55b90; 
frame = (200 28; 200 200); autoresize = RM+BM; 
layer = <CALayer: 0x7fe0f0f54000>>
View not found in container hierarchy: <UILabel: 0x7fe0f0f71810; 
frame = (200 28; 200 200); text = '0%'; userInteractionEnabled = NO; 
layer = <_UILabelLayer: 0x7fe0f0f71970>>
That view's superview: <UIView: 0x7fe0f0f56760; frame = (0 0; 375 667); 
autoresize = W+H; layer = <CALayer: 0x7fe0f0f56a30>>

and

2014-12-24 13:26:40.334 circle[28901:2153934] *** Terminating app due to uncaught exception
'NSGenericException', reason: 
'Unable to install constraint on view.  
Does the constraint reference something from outside the subtree of the view?  
That's illegal. 
constraint:<NSLayoutConstraint:0x7fe0f0f750d0 
MyUIView:0x7fe0f0f55b90.centerX == UILabel:0x7fe0f0f71810'0%'.centerX> 
view:< MyUIView: 0x7fe0f0f55b90; 
frame = (200 28; 200 200); autoresize = RM+BM; layer = <CALayer: 0x7fe0f0f54000>>'

Also, adding the constraint to the superview like this:

[self.superview addConstraint:xPosConstraint];

...causes the debugger to break the constraint because it can't be satisfied.

Beginning to hate auto layout...

****Edit**** Fixed it. Gah. Just needed to add this:

[self.myLabel setTranslatesAutoresizingMaskIntoConstraints:NO];