71

I've read the documentation. But I'm still not sure when I need to not set it to false. In the code below if I set it to false I won't see the header at all. If I leave it as true, then everything is fine.

The following in View debug hierarchy will give a warning "width and position are ambiguous".

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    let header = UIView()
    header.translatesAutoresizingMaskIntoConstraints = false
    header.backgroundColor = .orange
    header.heightAnchor.constraint(equalToConstant: 10).isActive = true

    return header
}

I thought whenever I need to modify anything in the code I would have to set translatesAutoresizingMaskIntoConstraints to false.

Perhaps it's more correct to say if you need to remove all its constraints then set it to false and then add what you like, and in that case you would need to add constraints for all 4 sides.

However, if you need to just keep what the system provides to you, in this case that would be the tableView managing its position and width then leave to true.

Is that right?

mfaani
  • 33,269
  • 19
  • 164
  • 293
  • 13
    If you set it to `false`, then the frame is ignored and positioning and size must be fully specified by `NSLayoutConstraint`s. If you set it to `true`, then the `frame` will be translated into constraints by iOS. – vacawama Dec 13 '17 at 18:54
  • 1
    @vacawama if I set it to `true` what happens to the constraints that I add myself? Additionally what is the recommended way of adding constraints to `viewForHeaderInSection`? – mfaani Dec 13 '17 at 18:58
  • 1
    If it's set to `true`, and you add your own constraints you will get constraint conflicts and the system will make its best guess which ones to use, which you might get lucky and it seems to work, but it will surely fail for the customer! – vacawama Dec 13 '17 at 19:00
  • @vacawama If you've provided a solution in your comments, I didn't get it :/ Your saying it could create conflicts. So how am I suppose to add a height constraint to this? (I don't want to use frames, because I want to you use dynamic header heights.) – mfaani Dec 13 '17 at 19:03
  • Maybe [this](http://roadfiresoftware.com/2015/05/how-to-size-a-table-header-view-using-auto-layout-in-interface-builder/) will help. – vacawama Dec 13 '17 at 19:17
  • More [interesting reading](https://spin.atomicobject.com/2017/08/11/swift-extending-uitableviewcontroller/). – vacawama Dec 13 '17 at 19:43
  • A very [helpful and related question](https://stackoverflow.com/questions/47947773/how-does-addsubview-work-with-intrinsicsizes) – mfaani Jun 14 '18 at 20:08
  • Now, I am totally confused? **GOAL** = rotate the Simulator in-place and have my SKScene automatically resize and fill the UIScreen, whether it's to Portrait or to Landscape. When I click on my Main View controller in the Project Navigator (on the left) and click its View(in the middle) and finally on the Size Inspector (on the right), I see the **multiple arrow graphic** which depicts **Autoresizing**. (1) Isn't this the place for adding the constraints? and (2) Why can't I get the red rectangle centered? It seems to me that having the red rectangle centered is exactly what I want? –  Dec 21 '22 at 09:01
  • @John you should ask a new question – mfaani Dec 21 '22 at 13:05
  • @John I see you've been on the site for 45 days. Welcome aboard. You should remove all the above comments. If you feel like your question is related and helpful for others to learn from, then link that question on the original question in this page. Then others can see... – mfaani Dec 21 '22 at 21:12

3 Answers3

83

translatesAutoresizingMaskIntoConstraints needs to be set to false when:

  1. You Create a UIView-based object in code (Storyboard/NIB will set it for you if the file has autolayout enabled),
  2. And you want to use auto layout for this view rather than frame-based layout,
  3. And the view will be added to a view hierarchy that is using auto layout.

In this case not all of these are true. Specifically, point 2.

After you return the header view from viewForHeaderInSection it is added to the table view and its frame is set based on the current width of the table view and the height you return from heightForHeaderInSection.

You can add subviews to the root header view (header in your code) and use constraints to layout those subviews relative to the header view.

You have discovered the reason why you can't use autolayout for the header view itself in your comments; at the time you create the view it isn't yet part of the view hierarchy and so you cannot constrain its edges to anything.

In order to have dynamic header sizing, you will need to add subviews to your header view and add constraints between those subviews and header. Then, auto layout can use the intrinsic content size of header to determine the header view size.

Since you are not constraining the frame of header, do not set translatesAutoresizingMaskIntoConstraints to false. You will need to ensure that you have sufficient constraints on your subviews for auto layout to determine the size of header.

You will need a continuous line of constraints from top to bottom and potentially some height constraints for your subviews if the intrinsic content size of that subview is not sufficient.

Any subviews you add to header do need translatesAutoresizingMaskIntoConstraints set to false

You also need to return something from estimatedHeightForHeaderInSection - the closer to your actual header height the better - if you are using tableview.sectionHeaderHeight = UITableViewAutomaticDimension

Michal Šrůtek
  • 1,647
  • 16
  • 17
Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • Interesting. So most answers including the accepted answer from [this highly viewed question](https://stackoverflow.com/questions/29462331/is-it-possible-to-obtain-a-dynamic-table-view-section-header-height-using-auto-l?rq=1) are misleading I guess – mfaani Dec 13 '17 at 21:53
  • Actually I just command clicked on `UITableViewAutomaticDimension` and these are the comments: "// Returning this value from tableView:heightForHeaderInSection: or tableView:heightForFooterInSection: results in a height that fits the value returned from // tableView:titleForHeaderInSection: or tableView:titleForFooterInSection: if the title is not nil. " – mfaani Dec 13 '17 at 21:55
  • 1
    Sorry, I have clarified the last paragraph of my answer; You can't use auto layout for the `header` view, but you can use auto layout for subviews in that view and then it should work for you. – Paulw11 Dec 13 '17 at 21:58
  • 2
    The way I see it now is: using the translated constraints the header is constrained from all 4 edges to its superview. If I set the `translatesAutoResizingMaskIntoConstraints` for the header itself to `false` all those will be erased. But I need them, so I have to keep it `true`. *Then* I'm adding more constraints for its subviews. For those subviews, they all need `translatesAutoResizingMaskIntoConstraints` set to `false`, any constraints they add to the header won't be conflicting to the translated constraints... – mfaani Dec 13 '17 at 22:04
  • That is correct. The tableview will take care of any constraints required for the `header` view (or set its frame directly, it shouldn't matter to you) – Paulw11 Dec 13 '17 at 22:13
  • about your last edit, not sure if you did see my first comment. It works...but if you're returning `nil` for your header, then it will just use the estimate height. Actually it didn't use the estimate. My estimate was 44, but when I I inspected it using the view debug hierarchy, it showed 28... – mfaani Dec 13 '17 at 23:25
  • Yes, but if you don't implement the `estimatedHeightForHeaderInSection` you won't see any section headers if you are using automatic dimension for the height – Paulw11 Dec 13 '17 at 23:41
  • Thanks for this explanation. However, could you kindly help shed insight as to how the system is creating a mysterious value with a `NSAutoresizingMaskLayoutConstraint`? https://stackoverflow.com/questions/53790691/debugging-autolayout-conflict-because-of-nsautoresizingmasklayoutconstraint-set – Crashalot Dec 15 '18 at 08:31
  • "Any subviews you add to header do need translatesAutoresizingMaskIntoConstraints set to false" why is this exactly? – Simon McNeil Oct 20 '20 at 14:58
  • Because you set it to false when you are using autolayout. – Paulw11 Oct 20 '20 at 19:22
55
  • For programmatically created view default is true and for views from Interface Builder default is false

    If the property is (or set to) True, the system automatically creates a set of constraints based on the view’s frame and its autoresizing mask. And if you add your own constraints, they inevitably conflict with the autogenerated constraints. This creates an unsatisfiable layout. So When programmatically instantiating views, be sure to set their translatesAutoresizingMaskIntoConstraints property to NO.

Forge
  • 6,538
  • 6
  • 44
  • 64
PANKAJ VERMA
  • 3,450
  • 1
  • 16
  • 15
  • 3
    "When programmatically instantiating views, be sure to set their translatesAutoresizingMaskIntoConstraints property to NO" - Actually, not always but only if you want to create your own constraints to deal with Auto Layout. If you prefer dealing with frames then you shouldn't set this value to `false` :) – Legonaftik May 03 '20 at 03:12
2

With PANKAJ VERMA's answer, it finally makes sense.

In my case, I have an ImageView and only set 2 constraints, yet the error shows that I have more constraints and LayoutConstraints was Unable to simultaneously satisfy constraints:

        view.addSubview(imageView)
        let yConstraint = imageView.centerYAnchor.constraint(equalTo: layout.centerYAnchor)
        yConstraint.identifier = "yConstraint"
        let xConstraint = imageView.centerXAnchor.constraint(equalTo: layout.centerXAnchor)
        xConstraint.identifier = "xConstraint"

Error message:

[LayoutConstraints] 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) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x600000089360 h=--& v=--& UIImageView:0x7fc1782087b0.minY == 0   (active, names: '|':UIView:0x7fc176406220 )>",
    "<NSAutoresizingMaskLayoutConstraint:0x600000089220 h=--& v=--& UIImageView:0x7fc1782087b0.height == 0   (active)>",
    "<NSLayoutConstraint:0x600000088c30 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x600001a880e0'UIViewLayoutMarginsGuide']-(34)-|   (active, names: '|':UIView:0x7fc176406220 )>",
    "<NSLayoutConstraint:0x600000088cd0 'UIView-topMargin-guide-constraint' V:|-(48)-[UILayoutGuide:0x600001a880e0'UIViewLayoutMarginsGuide']   (active, names: '|':UIView:0x7fc176406220 )>",
    "<NSLayoutConstraint:0x600000088d70 'yConstraint' UIImageView:0x7fc1782087b0.centerY == UILayoutGuide:0x600001a880e0'UIViewLayoutMarginsGuide'.centerY   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600000088d70 'yConstraint' UIImageView:0x7fc1782087b0.centerY == UILayoutGuide:0x600001a880e0'UIViewLayoutMarginsGuide'.centerY   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.

There was basically an almost identical error log for the 2nd constraint ("xConstraint") I set. As you can see in the error logs, I am "over-constraining" my UI. Along with 'yConstraint', I also have 4 other constraints. I believe the constraints are in a tuple, hence the paranthesis around them. XCode tries to be helpful by hinting "(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)", but personally I don't think this is helpful enough.


What is "Autoresizing Mask"?

I guess its important to know what this means, as this is being converted to constraints, hence the name translatesAutoresizingMaskIntoConstraints. Its an instance property of UIView containing an integer bit mask. It holds onto bits that you can toggle on and off for features like "flexible left margin" and "flexible height" (more of them here).

When a view’s bounds change, that view automatically resizes its subviews according to each subview’s autoresizing mask.

source

So to summarize the Autoresizing Mask, it holds onto the autoresize features you want, like flexible height and width.

Ben Butterworth
  • 22,056
  • 10
  • 114
  • 167