Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better workaround for unsatisfiable layout constraints for initially zero-sized view?

Tags:

ios

autolayout

Though not consequential it is quite annoying to see these warnings:

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:0x19288a20 V:|-(6)-[UILabel:0x19288640]   (Names: '|':_UITableViewHeaderFooterContentView:0x192885b0 )>",
    "<NSLayoutConstraint:0x19288a70 V:[UILabel:0x19288640]-(6)-|   (Names: '|':_UITableViewHeaderFooterContentView:0x192885b0 )>",
    "<NSAutoresizingMaskLayoutConstraint:0x19289cd0 h=--& v=--& V:[_UITableViewHeaderFooterContentView:0x192885b0(0)]>" )

Will attempt to recover by breaking constraint  <NSLayoutConstraint:0x19288a70 V:[UILabel:0x19288640]-(6)-|   (Names: '|':_UITableViewHeaderFooterContentView:0x192885b0 )>

There is nothing wrong of my constraints. The issue occurs when UIKit tries to do layout for the UITableViewHeaderFooterView with these constraints when the view is initially of zero size. Of course it is impossible to satisfy any constraints with any positive metrics.

One obvious workaround is to set a lower-than-UILayoutPriorityRequired priority or use NSLayoutRelationLessThanOrEqual instead of NSLayoutRelationEqual for each positive metrics. But then I need to add these crutches to all of my constraints on all of my views. Not to mention that what I really want are hard and fast not optional constraints.

Another workaround is to set a initial frame for UITableViewHeaderFooterView. But considering its designate init method is -initWithReuseIdentifier: not -initWithFrame: and it is the responsibility of UITableView and UITableViewDelegate to specify frame for UITableViewHeaderFooterView, it neither feels a good workaround.

So any better ones?

like image 860
an0 Avatar asked Aug 23 '13 03:08

an0


People also ask

What are two properties that auto layout constraints control on a UIView?

Auto Layout defines margins for each view. These margins describe the preferred spacing between the edge of the view and its subviews. You can access the view's margins using either the layoutMargins or layoutMarginsGuide property.

How do you add constraints in storyboard IOS?

Open the Align menu with the yellow button selected and check Horizontally in Container, then click Add 1 Constraint. Now, select both buttons at the same time using the Shift key and, in the Align menu, check Leading Edges. Again, actually install the constraint by clicking Add 1 Constraint.

What is UIView encapsulated layout width?

If you see the error message contains UIView-Encapsulated-Layout-Width , which means your constraints relative to width conflict with it. For example, you set label constrains: [ leading , trailing , bottom , top ] or [ CenterX , leading , bottom , top ] leading trailing and CenterX are for width.


1 Answers

I think your particular problem stems from attempting to set "container" sizing constraints on an instance of UITableViewHeaderFooterView. The issue is similar to wanting to have cells size themselves based on auto layout asked here.

For this question specifically, the view has a size of zero, yet the constraints dictate the view be at least 12pt on a dimension (which violates the current state). This is especially violated in this case and cannot be dealt with due to the header/footer view being sized using frames/autoresizing-masks and not auto-layout, thus the exception.

You have two options for this case:

  1. Make your constraints less "required" like you suggested in the second part of your question by making the constraints have a priority less than 1000.
  2. Defer the installation of your constraints until the header/footer has a defined size. You already know your view is going to have a size and that your constraints make sense. Your constraints simply don't make sense to the system for a view that is less than 12pt on an edge (horizontally, in your case). You could hack it together by:
    1. Checking out layoutSubviews for a non-zero bounds.size, or (if you're not doing it already)
    2. Install your constraints (only once) in updateConstraints of your UITableViewHeaderFooterView subclass.
    3. You could also combine the two above solutions and only install your auto-layout constraints in updateConstraints if you detect that self.bounds.size is not CGSizeZero (this would be the proper solution).
like image 65
larsacus Avatar answered Oct 22 '22 20:10

larsacus