I create a custom IB-designable view (see code below) which renders correctly in IB and also works fine when running it. However, in get this warning about the view being misplaced and I cannot manually resize the view in Interface Builder (when touching a resize handle, the view will jump around in its container).
I get the same or similar behavior for all kinds of different layouts. Do you have an idea if I'm doing something wrong here, or is this just a bug in IB?
(PS: I cannot just ignore the warning)

EDIT: added screenshot of constraints:

Here is the code (header):
IB_DESIGNABLE
@interface AKATestView : UIView
@end
Implementation:
@interface AKATestView()
@property(nonatomic)BOOL subviewsCreated;
@property(nonatomic)BOOL subviewConstraintsCreated;
@property(nonatomic)NSDictionary* views;
@end
@implementation AKATestView
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self setupAfterInit];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setupAfterInit];
}
return self;
}
- (void)setupAfterInit
{
[self createSubviews];
}
- (void)createSubviews
{
if (!self.subviewsCreated)
{
self.translatesAutoresizingMaskIntoConstraints = NO;
UILabel* labelView = [[UILabel alloc] initWithFrame:CGRectZero];
labelView.text = @"Name";
labelView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:labelView];
UITextField* textField = [[UITextField alloc] initWithFrame:CGRectZero];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.placeholder = @"Enter some text";
textField.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:textField];
UILabel* errorMessageLabel = [[UILabel alloc] initWithFrame:CGRectZero];
errorMessageLabel.text = @"Error message";
errorMessageLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:errorMessageLabel];
self.views = @{ @"label": labelView, @"editor": textField, @"errorMessageLabel": errorMessageLabel };
self.subviewsCreated = YES;
[self setNeedsUpdateConstraints];
}
}
- (void)updateConstraints
{
if (!self.subviewConstraintsCreated)
{
NSDictionary* metrics =
@{ @"pt": @(4), @"pr": @(4), @"pb": @(4), @"pl": @(4),
@"labelWidth": @(100),
@"errorPl": @(4 + 100 + 4),
@"hsLabelEditor": @(4), @"vsEditorError": @(2)
};
NSArray* specs =
@[ @{ @"format": @"H:|-(pl)-[label(labelWidth)]-(hsLabelEditor)-[editor]-(pr)-|",
@"options": @(NSLayoutFormatAlignAllFirstBaseline) },
@{ @"format": @"V:|-(pt)-[editor]-(vsEditorError)-[errorMessageLabel]-(pb)-|",
@"options": @(NSLayoutFormatAlignAllLeading|NSLayoutFormatAlignAllTrailing) }
];
for (NSDictionary* spec in specs)
{
NSString* format = spec[@"format"];
NSUInteger options = ((NSNumber*)spec[@"options"]).unsignedIntegerValue;
NSArray* constraints = [NSLayoutConstraint constraintsWithVisualFormat:format
options:options
metrics:metrics
views:self.views];
[self addConstraints:constraints];
}
self.subviewConstraintsCreated = YES;
}
[super updateConstraints];
}
@end
Try removing self.translatesAutoresizingMaskIntoConstraints = NO; in your createSubviews method. IB seems to be relying on this translation to come up with correct measurement on the designer. I had the exact same problem and this fixed it.
I still have translatesAutosizingMaskIntoConstraints to NO for subviews. I confirmed that there aren't any extra constraints generated even with this set to YES. Hope it's the case for you too!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With