NSLayoutConstrain - Will attempt to recover by breaking constraint - Programmatically Creating Constraints [duplicate] - ios

This question already has answers here:
Unable to simultaneously satisfy constraints, will attempt to recover by breaking constraint
(17 answers)
Closed 6 years ago.
It runs fine and nothing is wrong except that I receive this error.
Below is my code.
NSDictionary *views = #{#"container":self.containerView,
#"head":self.headImageView,
#"userName":self.userNameLabel,
#"userTitle":self.userTitleLabel,
#"line":self.infoSeparatorLine,
#"articleTitle":self.articleTitleLabel
};
float headWidthAndHeight = 50;
NSDictionary *metrics = #{#"headWH":#(headWidthAndHeight),
#"userLabelWH":#(headWidthAndHeight/2),
};
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[container]|" options:0 metrics:nil views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-10-[container]|" options:0 metrics:nil views:views]];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-15-[head(headWH)]-5-[userName]-15-|" options:0 metrics:metrics views:views]];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-15-[head(headWH)]-5-[userTitle]-15-|" options:0 metrics:metrics views:views]];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[line]|" options:0 metrics:metrics views:views]];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-15-[articleTitle]-15-|" options:0 metrics:metrics views:views]];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[head(headWH)]-0-[line(1)]-8-[articleTitle]|" options:0 metrics:metrics views:views]];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[userName(userLabelWH)]-0-[userTitle(userLabelWH)]" options:0 metrics:metrics views:views]];
Below is the error message I receive in the debug area.
How do I fix it?

[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[head(headWH)]-0-[line(1)]-8#999-[articleTitle]|" options:0 metrics:metrics views:views]];
Change priority below 1000 for broken constraint.

Related

Change constraints based on text length

I have two labels, that are ordered like this:
H:[label1]-10-[label2]
I want to change their order, based on the first label's length. So, if its text won't fit on one line, I want to change the constraints to look like this:
V:[label1]-2.5-[label2]
Here are my constraints right now:
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_carLabel]-2.5-[_statusLabel]|" options:0 metrics:nil views:views]];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_carLabel]|" options:0 metrics:nil views:views]];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_statusLabel]|" options:0 metrics:nil views:views]];
And this is how I want them to look, when _carLabel won't fit in one line:
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_carLabel]-10-[_statusLabel]|" options:0 metrics:nil views:views]];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_carLabel]|" options:0 metrics:nil views:views]];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_statusLabel]|" options:0 metrics:nil views:views]];
How would I do this?
I think your best bet would be to conditionally apply constraints based on the size of the label. I don't believe there's a way to add both constraints and have this work how you described. (Though if it is possible it will likely have to do with setting the priority of each constraint #"[label1]-10#99-[label2]" and #"V:[label1]-2.5#98-[label2] but I was unable to get that to work. The code below however seems to do what you're looking for.
UILabel *label1 = [[UILabel alloc] init];
label1.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:label1];
[label1 setText:#"Small text"];
// [label1 setText:#"Some really long text to test the other scenario also works"];
UILabel *label2 = [[UILabel alloc] init];
label2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:label2];
[label2 setText:#"Small text 2"];
[label1 sizeToFit];
if (label1.frame.size.width + kPadding + label2.frame.size.width < self.view.frame.size.width) {
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[label1]-padding#100-[label2]"
options:0
metrics:#{#"padding": #(kPadding)}
views:NSDictionaryOfVariableBindings(label1, label2)]];
} else {
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[label1]-2.5#100-[label2]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(label1, label2)]];
}

NSLayoutConstraint, sub-viewing a UIView in a table view cell not working

So I am using a project that I found on Github — https://github.com/kmonaghan/CBPWordPress — and am trying to get a handle on it.
Essentially, what I want to do is create the floating "Cards" illusion that an app like Facebook has. The way that I have accomplished this in the past is by creating a subview UIView, rounding the corners, etc. before putting the title label, author name inside of that view. The issue is that I have typically done that with storyboards, while this example programmatically lays things out.
After toying around with it, I thought I had figured it out. This is how I set up the -(void)updateConstraints method:
(void)updateConstraints
{
if (!self.constraintsUpdated) {
self.contentView.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.frame), CBPLargePostPreviewTableViewCellHeight);
NSDictionary *views = #{#"postCommentLabel": self.postCommentLabel,
#"postDateLabel": self.postDateLabel,
#"postImageView": self.postImageView,
#"postTitleLabel": self.postTitleLabel,
#"roundedBackground": self.roundedBackground};
NSDictionary *metrics = #{#"padding": #(CBPPadding)};
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(4)-[roundedBackground]-(4)-|"
options:0
metrics:metrics
views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(4)-[roundedBackground]-(4)-|"
options:0
metrics:metrics
views:views]];
[self.roundedBackground addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(5)-[postTitleLabel]-(5)-[postImageView(150)]-(5)-[postDateLabel]-(5)-|"
options:0
metrics:nil
views:views]];
[self.roundedBackground addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(padding)-[postTitleLabel]-(padding)-|"
options:0
metrics:metrics
views:views]];
[self.roundedBackground addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(padding)-[postImageView]-(padding)-|"
options:0
metrics:metrics
views:views]];
[self.roundedBackground addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(padding)-[postDateLabel]-(>=0)-[postCommentLabel]-(padding)-|"
options:0
metrics:metrics
views:views]];
[self.roundedBackground addConstraint:[NSLayoutConstraint constraintWithItem:self.postCommentLabel
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.postDateLabel
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0]];
self.constraintsUpdated = YES;
}
[super updateConstraints];
}
But upon running I get this error: [__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[4]'
I have tried creating bounds for the view, but to no avail. Does anybody have any suggestions? If there is a better approach to creating the effect I am looking for, I am also open to that.
It seems that you use roundedBackground in visual format strings, but have background
key in your views dict.

How do I auto layout constraints when I add a new view such as a error message to the top of a main view

This is my controller as it loaded
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.mainTitleText];
[self.view addSubview:self.subTitle];
[self.view addSubview:self.tableView];
[self.view addSubview:self.acceptBtn];
[self.view addSubview:self.notAcceptBtn];
[self addConstraints];
}
I add my constraints here
- (void)addConstraints {
id metrics = #{ #"textHMargin": #10, #"topMargin": #110, #"margin": #8, #"titleHeight": #60, #"subtitleHeight": #40, #"tableHeight": #88 };
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-textHMargin-[mainTitleText]-textHMargin-|" options:0 metrics:metrics views:self.views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-textHMargin-[subTitle]-textHMargin-|" options:0 metrics:metrics views:self.views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[tableView]|" options:0 metrics:metrics views:self.views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-margin-[acceptBtn]-margin-|" options:0 metrics:metrics views:self.views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-margin-[notAcceptBtn]-margin-|" options:0 metrics:metrics views:self.views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-topMargin-[mainTitleText(titleHeight)]-margin-[subTitle(subtitleHeight)]-[tableView(tableHeight)]-margin-[acceptBtn]-margin-[notAcceptBtn]" options:0 metrics:metrics views:self.views]];
}
This is where I'm getting stuck. When I add my error message view it does not stack on top and push everything down.
- (void)acceptAction:(id)sender {
[self.activeTextfield resignFirstResponder];
if (self.airlineInfo.flightNumber && self.airlineInfo.airlineDescription) {
//TODO: success code
} else {
//show error
id metrics = #{ #"textHMargin": #10, #"topMargin": #110, #"margin": #8, #"titleHeight": #60, #"subtitleHeight": #40, #"tableHeight": #88 };
[self.view addSubview:self.infoMessage];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-textHMargin-[infoMessage]-textHMargin-|" options:0 metrics:metrics views:self.views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-topMargin-[infoMessage(20)]-margin-[mainTitleText(titleHeight)]-margin-[subTitle(subtitleHeight)]-[tableView(tableHeight)]-margin-[acceptBtn]-margin-[notAcceptBtn]" options:0 metrics:metrics views:self.views]];
}
}
view http://kgaddy.com/errorView.jpg.
What I would do is not use constraints for this extra view at all. Just stick it into the interface. But change the constant on your existing top view to a larger value, thus pushing it down and pushing down everything that is pinned to it below it.
So, right now, you are saying:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-topMargin-[mainTitleText(titleHeight)]-margin-[subTitle(subtitleHeight)]-[tableView(tableHeight)]-margin-[acceptBtn]-margin-[notAcceptBtn]" options:0 metrics:metrics views:self.views]];
Instead of just adding those constraints directly, first keep a reference to them; then add them. That way you can sneakily remove those constraints later! Then you do the same thing again but with a push-down value at the top:
[self.view removeConstraints:self.verticalContraints]; // previously saved
self.verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(40)-topMargin-[mainTitleText(titleHeight)]-margin-[subTitle(subtitleHeight)]-[tableView(tableHeight)]-margin-[acceptBtn]-margin-[notAcceptBtn]" options:0 metrics:metrics views:self.views]];
[self.view addConstraints:self.verticalConstraints];
Notice the "40" that I snuck in there. You can fix that to a better value experimentally. You see from this how to swap out a bunch of constraints and put a different set in their place.

uiscrollview doesn't scroll because of autolayout

I know that there are already many answers to my questions, but I've tested each one of these and I still have the problem.
I have a UIScrollView which contains a UIView, I want active autolayout for an animation. But because of this, my scrollview doesn't scroll.
This is my code:
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_scrollView, _containerScrollView);
[_scrollView setScrollEnabled:YES];
[_scrollView setContentSize:CGSizeMake(_scrollView.frame.size.width, CGRectGetHeight(_containerScrollView.frame))];
_scrollView.userInteractionEnabled = YES;
_scrollView.delaysContentTouches = YES;
[self.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_scrollView]|" options:0 metrics:0 views:viewsDictionary]];
[self.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_scrollView]|" options:0 metrics:0 views:viewsDictionary]];
[_scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_containerScrollView]|" options:0 metrics:0 views:viewsDictionary]];
[_scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_containerScrollView]|" options:0 metrics:0 views:viewsDictionary]];
Somebody can explain me why doesn't it work?
Try to set your scrollView's Content size int "viewDidLayoutSubviews" method with keeping the autolayouts set.
-(void)viewDidLayoutSubviews
{
[self.itemList setContentSize:CGSizeMake(required_width, required_height)];
}

NSLayoutConstraint setup

I'm trying to setup a panel to display some information. I'm having trouble getting the autolay out to work as i want.
here's what I'm trying to do:
I have a headerView, a UIImageView and 5 labels. I want the labels to line up vertically and i want them 8 spacing from the UIImageView. I can line them up vertically easily enough:
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[headerView]-[acresLabel]-[addedLabel(==acresLabel)]-[typeLabel(==acresLabel)]-[zonesLabel(==acresLabel)]-[sceneLabel(==acresLabel)]-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(headerView, acresLabel, addedLabel, typeLabel, zonesLabel, sceneLabel)]];
But getting them to line up off the image view is proving tedious/verbose:
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[acresLabel]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(imageView, acresLabel)]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[addedLabel]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(imageView, addedLabel)]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[typeLabel]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(imageView, typeLabel)]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[zonesLabel]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(imageView, zonesLabel)]];
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[sceneLabel]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(imageView, sceneLabel)]];
Seems like a better way to do this then set up a constraint for each label to the image view. I tried adding NSLayoutFormatAlignAllCenterX to the first constrain, but it sets them all center to the content view's center X, doesn't line the label's center X up with each other. NSLayoutFormatAlignAllBaseline gives an error and crash when used vertically.
I'll have to do this again for the data (Acres: 'value').
You're on the right track with NSLayoutFormatAlignAllCenterX. All you need to do differently is isolate V:[headerView]-[acresLabel] from the rest of the constraint, since you don't want headerView's CenterX to be aligned with the 5 labels'.
// NSDictionary* views ;
[NSLayoutConstraint constraintsWithVisualFormat:#"V:[headerView]-[acresLabel]" options:0 metrics:nil views:views] ;
// Use any of the horizontal NSLayoutFormats (NSLayoutFormatAlignAllLeft, NSLayoutFormatAlignAllRight, NSLayoutFormatAlignAllLeading, NSLayoutFormatAlignAllTrailing, NSLayoutFormatAlignAllCenterX)
[NSLayoutConstraint constraintsWithVisualFormat:#"V:[acresLabel]-[addedLabel(==acresLabel)]-[typeLabel(==acresLabel)]-[zonesLabel(==acresLabel)]-[sceneLabel(==acresLabel)]-|" options:NSLayoutFormatAlignAllCenterX metrics:0 views:views] ;
[NSLayoutConstraint constraintsWithVisualFormat:#"H:[imageView]-[acresLabel]" options:0 metrics:nil views:views] ;

Resources