Using auto layout and systemLayoutSizeFittingSize - ios

I have a really simple view that I cannot for the life of me figure out the problem. I have successfully used auto layout and systemLayoutSizeFittingSize for fairly complex custom UITableViewCells. This is my first time using it for a UIView (to be used in a UITableView.tableHeaderView) and I cannot get it to work.
I have a simple label in the view that I want to cover the entire view. I have added the Trailing, Leading, Top, and Bottom constraints to the label against the parent's corresponding edges. When I do this, systemLayoutSizeFittingSize computes the correct height, but I get the following error:
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x7fbb71d9a310 V:|-(5)-[UILabel:0x7fbb71df5120'Test Label'] (Names: '|':mailapp.MailTableHeaderView:0x7fbb71d2c490 )>",
"<NSLayoutConstraint:0x7fbb71d2ebf0 UILabel:0x7fbb71df5120'Test Label'.bottom == app.HeaderView:0x7fbb71d2c490.bottom - 5>",
"<NSLayoutConstraint:0x7fbb71de31d0 V:[app.HeaderView:0x7fbb71d2c490(0)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7fbb71d2ebf0 UILabel:0x7fbb71df5120'Test Label'.bottom == app.HeaderView:0x7fbb71d2c490.bottom - 5>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Now, if I remove the "bottom" constraint on the label, auto layout works correctly but now systemLayoutSizeFittingSize returns 0.
What is the right way to make the constraints satisfy the auto layout engine but also to have systemLayoutSizeFittingSize compute the correct size?
As I mentioned, the most baffling thing is that I have used this successfully for complex auto layouts, but I noticed all those were UITableViewCells. I'm not sure if there is a difference.

I figured out the problem, but I don't understand why. For the UITableViewHeader, I cannot do the typical auto layout thing for the view. That is, I have to set translatesAutoresizingMaskIntoConstraints to be true. Effectively, I cannot use auto layout for the header view, and I have to set the frame manually.
Within the header view, I can use auto layout for the sub views successfully.
So my algorithm goes like this for constructing the tableHeaderView:
Create the header view with any arbitrary frame
Compute the constraints (of the header view's subviews)
Set the frame.width of the header view to match the parent tableView.frame.width
Layout the header view
Use systemLayoutSizeFittingSize to compute the height
Update the header view's frame.height
This works for me. I was not able to get it to work if I created the header view with translatesAutoresizingMaskIntoConstraints set to false.

As per the Apple Visual Format Language the following appears to be setting a '0' height constraint on your HeaderView.
E.g.
"<NSLayoutConstraint:0x7fbb71de31d0 V:[app.HeaderView:0x7fbb71d2c490(0)]>"
I would start by investigating this, as having a height of 0 will likely mess up your other label constraints for top and bottom spacing.

Related

iOS 8 Custom Self Sizing Table View : Unable to simultaneously satisfy constraints

In UITableViewController, I am using custom UITableView cell. This cell contains a UIImage control on left side of cell and two UILabels(one is for product name and other is for product description, which can be varying length) to the right of this UIImage. I have added Auto Layout constraints on all three controls. There is no issue in Auto Layout control. However when I run the app, I get the following error messages (one for each row in the table) and a couple of top rows are not as per auto layout constraints, but however when I scroll down and then scroll up, everything is rendered as per the auto layout constraints
Debug Log:
-----------------------------------------------------------------------------
- Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x170085ff0 H:[PFImageView:0x14ee1d350(60)]>",
"<NSLayoutConstraint:0x17408a500 PFImageView:0x14ee1d350.leading == UITableViewCellContentView:0x14ee1cdf0.leadingMargin + 7>",
"<NSLayoutConstraint:0x17408a5a0 UITableViewCellContentView:0x14ee1cdf0.trailingMargin == UILabel:0x14ed08580'Naturally Sandstone Slabs'.trailing + 10>",
"<NSLayoutConstraint:0x17408a5f0 H:[PFImageView:0x14ee1d350]-(11)-[UILabel:0x14ed08580'Naturally Sandstone Slabs']>",
"<NSLayoutConstraint:0x17008c6c0 'fittingSizeHTarget' H:[UITableViewCellContentView:0x14ee1cdf0(34)]>" )
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x170085ff0 H:[PFImageView:0x14ee1d350(60)]>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
The issue was because i was using a disclosure indicator in the table view. Lowering the priority of label's trailing-to-superview constraint. (I chose 990) fixed the issue.
Below is the link where i get the solution:
ios8 cell constraints break when adding disclosure indicator

Adding a button in dynamic TableViewCell

I have a label of dynamic size in a TableViewCell. I have pinned it to up,down,left and right and set Lines to 0 and it is working fine. Next, I add a button below the label and and pin it to top and left. and fix the width and height. But I am getting an error at runtime
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this: (1) look at each constraint and try to figure out which you
don't expect; (2) find the code that added the unwanted constraint or
constraints and fix it. (Note: If you're seeing
NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the
documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x7fcbc302f600 UILabel:0x7fcbc3034010'Digestion of food in the...'.top == UITableViewCellContentView:0x7fcbc30334a0.topMargin>",
"<NSLayoutConstraint:0x7fcbc3037e30 UITableViewCellContentView:0x7fcbc30334a0.bottomMargin == UILabel:0x7fcbc3034010'Digestion of food in the...'.bottom + 38>",
"<NSLayoutConstraint:0x7fcbc303a920 'UIView-Encapsulated-Layout-Height' V: [UITableViewCellContentView:0x7fcbc30334a0(43.5)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7fcbc3037e30
UITableViewCellContentView:0x7fcbc30334a0.bottomMargin ==
UILabel:0x7fcbc3034010'Digestion of food in the...'.bottom + 38>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. Here is the screenshot of my layout
Which constraint should I remove? I don't think I have added extra constraints
In interface builder check that there are no warnings (the yellow arrow on the side of the vc inspector) and check that the height of the label +the button and the margins don't exceed the cell height.
Also you said you pinned to the top, of what? The container or the label?
Use these constraint for as per your requirements:
OR
Follow these links Autolayout or Autolayout programatically
(OR)
For some reason, Xcode generates own default set of auto layout constraints on a NIB at build time. This is why I couldn't add any more manual constraints, because they were conflicting with the automatically added ones.
I resolved this the following way:
Open up the Storyboard view controller you're handling.
Select the view controller and select Editor > Resolve Auto Layout Issues > All Views in [ ] View Controller > Add Missing Constraints from the menu:
This will ensure that no additional build time constraints are created and all the constraints are now visible.-->Select all the constraints from your view controller:
This will ensure that no additional build time constraints are created and all the constraints are now visible.-->Check from the right pane the following check box: Placeholder - Remove at build time:
(This will ensure that no additional build time constraints are created and all the constraints are now visible.)
Now you can add all the auto layout constraints manually in the code.
you will have to provide some more info than that regarding the values you set in auto layout like the distance of the UILabel from top margin,down,left etc.
The problem might be that you specified the UIButton to be from top margin , it should be with respect to your UILabel as its below it so set the UIButton's vertical spacing property to the UILabel this makes sure the UIButton is placed below it.

What is the correct way to use UIScrollView?

I tried to setup a simple view which displays a text-only article with a headline. Here are the steps that I've done:
Create View Controller with its .xib file,
Create UIScrollView and places a UIView directly as the content wrapper,
Set the constraints [scrollview]-0-[superview] in top, bottom, leading, and trailing.
Set the constraints [content wrapper]-0-[scroll view] in top, bottom, leading, and trailing.
Set Width and Height to content wrapper as placeholder.
Add Label and UITextView as content wrapper's subviews.
Add constraints to the subviews.
Following this tutorial, I programmatically set content wrapper's leading = scrollview's superview left,
... And content wrapper's trailing = scrollview's superview right.
When I ran the code, it shows everything in place perfectly; The UIScrollView scrolls, margins are properly set, etc.
However, Xcode throws an exception:
2015-02-05 18:06:58.230 ScrollViewApp[5353:180401] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x7ff9fa49a3f0 H:[UIView:0x7ff9fa571560(600)]>",
"<NSLayoutConstraint:0x7ff9fa49b1a0 H:|-(0)-[UIView:0x7ff9fa571560] (Names: '|':UIScrollView:0x7ff9fa49a910 )>",
"<NSLayoutConstraint:0x7ff9fa49ce00 H:|-(0)-[UIScrollView:0x7ff9fa49a910] (Names: '|':UIView:0x7ff9fa49a840 )>",
"<NSLayoutConstraint:0x7ff9fa61c050 UIView:0x7ff9fa571560.right == UIView:0x7ff9fa49a840.trailing>",
"<NSLayoutConstraint:0x7ff9fa580970 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7ff9fa49a840(375)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7ff9fa49a3f0 H:[UIView:0x7ff9fa571560(600)]>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
After further googling, I found out that I can dismiss the warning by setting content wrapper's width (see step 5 above) priority to low; however it breaks the layout in interface builder. Take a look:
Compared to when it's set to High priority:
I know that in the end it makes no difference because it's both working as expected.. But I'm kind of curious as to why these things happen..
I'm trying to understand how UIScrollView works, but maybe I'm misunderstanding something; so, what is the proper way for setting up UIScrollView to work as expected?
Try to add a center horizontally constraint from your content wrapper to your scroll view.
To be honest, I really don't know why that works, i figured this one out by trial an error. If you want your view to be compatible different screen sizes, remove the width constraint of the content wrapper.
Hope it helped.
you can use scrollview like this. Add scrollview in design. Give it's left, top, right, bottom constraints in design. Add your subviews in scrollview. Add proper constraints for them. There is no need to add constraints in code. In viewDidLayoutSubviews set your scrollview's content size.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGRect boundsOfSelf = self.view.bounds;
scrollView.frame = boundsOfSelf;
[scrollView setContentSize: boundsOfSelf.size];
}

How to tell UITableView that a self-sizing cell's height is about to change?

I've got a UITableView whose contents are somewhat dynamic. It seems like every time I resize them, I hit this error:
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x15dbabf0 WKWebView:0x15da1650.top == UITableViewCellContentView:0x15eaedb0.topMargin>",
"<NSLayoutConstraint:0x15dbac20 UITableViewCellContentView:0x15eaedb0.bottomMargin == WKWebView:0x15da1650.bottom>",
"<NSLayoutConstraint:0x15db1360 V:[WKWebView:0x15da1650(158)]>",
"<NSLayoutConstraint:0x15ed0c00 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x15eaedb0(43.5)]>"
)
It's that last one - the one labeled UIView-Encapsulated-Layout-Height - that is breaking things. I want to get rid of it, or set it to a breaking priority, or something - but I can't seem to be able to tell UITableView to break it. I've tried every possible combination of setNeedsUpdateConstraints and setNeedsLayout on various views. I've tried removing all the constraints from the cell's contentView on updateConstraints. I've tried just calling beginUpdates and endUpdates - in that case, updateConstraints is never called & the constraints are not re-evaluated.
I'm at a loss, here. Without self-sizing cells, just calling begin/endUpdates used to trigger a re-calculation of the cell's dimensions. How do I do it now?
The WKWebView which you are using inside the content view is the most possible cause of breaking constraints. Also the height of any webView can be calculated only when the WebView has finished loading. For e.g in UIWebView the height of the UIWebView can be fetched appropriately only in the delgate method "didFinishLoadingWebView" method.
Also, the 'UIView-Encapsulated-Layout-Height' constraints supposedly does not get satisfied as the cell's intrinsic height calculated probably has a different value. Hence one can lower the priority of the relevant cell constraint to allow UIView-Encapsulated-Layout-Height to have precedence.

Auto layout constraints in code conflicting with sizes in XIB

I've set up a number of UILabels and UIButtons within 3 subviews in a storyboard. In code, I've defined auto layout constraints for all of these however for some reason when I run the app, the sizes that I have defined in the storyboard are conflicting with the constraints in code.
For example, one subview is positioned at 0,0 in the XIB with height 200 and width 320, simply for me to layout the elements before writing the code. There are no constraints in the storyboard.
This subview has a number of UILabels and UIButtons within it and their cumulative height is supposed to define the height of the subview. This should end up at 205pts height, however the log shows a conflict:
2014-06-02 16:45:38.506 discounter[11691:60b] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSIBPrototypingLayoutConstraint:0x109390160 'IB auto generated at build time for view with fixed frame' V:[UIView:0x109389010(200)]>",
"<NSLayoutConstraint:0x109249510 V:[UIView:0x109389010(205)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x109249510 V:[UIView:0x109389010(205)]>
I have set all my views to have translatesAutoresizingMaskIntoConstraints = NO so I'm at a loss as to why this is happening. It appears to be happening to a number of other elements too, but I have a feeling its probably the same reason why.
Can anyone help?
Thanks!
Add those constraints that you will replace in your code in your storyboard, and check their "remove at build time" properties. Like this:
Background:
This is a way for you to promise Xcode that you will add the constraint in code, and thus will prevent Xcode from auto generating the necessary constraints. The auto generation is necessary, as otherwise the runtime wouldn't be able to determine how to present the view in question. Generally, you should strive to define all your constraints in the storyboard. You could also IBOutlet a constraint to your code, and then edit its constant value when the app is ran, that way avoiding the tedious adding of constraints in your code.

Resources