2

I'm having some issues with Autolayout width on all screen sizes for a keyboard extension.

At first it worked fine, but then suddenly started spitting out a number of errors regardless of the width of the screen. I didn't change anything, I even tried deleting the app, cleaning the project, and laying out everything from scratch.

This is my layout:

| - 8 - (50) - >=8 - (130) - 8 - (130) - 8 - |
priority (50) = 750, everything else = 1000
  • There's a 8 point space between the superview and button 1, which has a width of 50, but a priority of 750.
  • Then there's a 8 point or greater space between button 1 and button 2, which has a width of 130.
  • Then there's a 8 point space between button 2 and button 3, which also has a width of 130.
  • Lastly there's a 8 point space between button 3 and the superview.

Screenshot of storyboard layout

This is somehow causing a problem on not only the 320 point wide 4 inch screen, but also the 375 point wide 4.7 inch screen and 414 point wide 5.5 inch screen.

As far as I see, there shouldn't be any problems as the max width of the items is (8+50+8+130+8+130+8) 342 points. This is less than both the 4.7 and 5.5 inch screens. On the 4 inch, I solve this by breaking the 50 point width on button 1, so the total is 320 points.

It looks fine on both the simulator and device, however the console spits out a number of Unable to simultaneously satisfy constraints errors (3 to be exact).

Here's the log:

1: (
"<NSLayoutConstraint:0x1740954a0 H:[UIButton:0x137e0cb80'Last sentence'(130)]>",
"<NSLayoutConstraint:0x1740955e0 H:[UIButton:0x137e0cda0'Pasteboard'(130)]>",
"<NSLayoutConstraint:0x174095810 H:|-(8)-[UIButton:0x137d0ba60]   (Names: '|':UIView:0x137e0c1b0 )>",
"<NSLayoutConstraint:0x1740958b0 H:[UIButton:0x137d0ba60]-(>=8)-[UIButton:0x137e0cda0'Pasteboard']>",
"<NSLayoutConstraint:0x174095950 H:[UIButton:0x137e0cda0'Pasteboard']-(8)-[UIButton:0x137e0cb80'Last sentence']>",
"<NSLayoutConstraint:0x1740959f0 H:[UIButton:0x137e0cb80'Last sentence']-(8)-|   (Names: '|':UIView:0x137e0c1b0 )>",
"<NSLayoutConstraint:0x170094ff0 'UIView-Encapsulated-Layout-Width' H:[UIView:0x137e0c1b0(55)]>"
)
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x1740955e0 H:[UIButton:0x137e0cda0'Pasteboard'(130)]>

2: (
"<NSLayoutConstraint:0x1740954a0 H:[UIButton:0x137e0cb80'Last sentence'(130)]>",
"<NSLayoutConstraint:0x174095810 H:|-(8)-[UIButton:0x137d0ba60]   (Names: '|':UIView:0x137e0c1b0 )>",
"<NSLayoutConstraint:0x1740958b0 H:[UIButton:0x137d0ba60]-(>=8)-[UIButton:0x137e0cda0'Pasteboard']>",
"<NSLayoutConstraint:0x174095950 H:[UIButton:0x137e0cda0'Pasteboard']-(8)-[UIButton:0x137e0cb80'Last sentence']>",
"<NSLayoutConstraint:0x1740959f0 H:[UIButton:0x137e0cb80'Last sentence']-(8)-|   (Names: '|':UIView:0x137e0c1b0 )>",
"<NSLayoutConstraint:0x170094ff0 'UIView-Encapsulated-Layout-Width' H:[UIView:0x137e0c1b0(55)]>"
)
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x1740954a0 H:[UIButton:0x137e0cb80'Last sentence'(130)]>

3: (
"<NSLayoutConstraint:0x174095810 H:|-(8)-[UIButton:0x137d0ba60]   (Names: '|':UIView:0x137e0c1b0 )>",
"<NSLayoutConstraint:0x1740958b0 H:[UIButton:0x137d0ba60]-(>=8)-[UIButton:0x137e0cda0'Pasteboard']>",
"<NSLayoutConstraint:0x174095950 H:[UIButton:0x137e0cda0'Pasteboard']-(8)-[UIButton:0x137e0cb80'Last sentence']>",
"<NSLayoutConstraint:0x1740959f0 H:[UIButton:0x137e0cb80'Last sentence']-(8)-|   (Names: '|':UIView:0x137e0c1b0 )>",
"<NSLayoutConstraint:0x170094ff0 'UIView-Encapsulated-Layout-Width' H:[UIView:0x137e0c1b0(0)]>"
)
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x1740958b0 H:[UIButton:0x137d0ba60]-(>=8)-[UIButton:0x137e0cda0'Pasteboard']>

I've been scratching my head with this all evening. Do you guys have any suggestions?

Aleksander
  • 2,735
  • 5
  • 34
  • 57

2 Answers2

2

For whatever reason, the superview is, at least temporarily, only 55 points wide. From the log you quoted:

"<NSLayoutConstraint:0x174095810 H:|-(8)-[UIButton:0x137d0ba60]   (Names: '|':UIView:0x137e0c1b0 )>",
...
"<NSLayoutConstraint:0x1740959f0 H:[UIButton:0x137e0cb80'Last sentence']-(8)-|   (Names: '|':UIView:0x137e0c1b0 )>",
"<NSLayoutConstraint:0x170094ff0 'UIView-Encapsulated-Layout-Width' H:[UIView:0x137e0c1b0(55)]>"

So, | (the superview's edges) is UIView:0x137e0c1b0 and that's constrained to 55 points wide (UIView:0x137e0c1b0(55)).

That view is presumably controlled by the frameworks. You need to accommodate it having any arbitrary width (even 0, as in the last exception). To do that, make one of the horizontal spacing constraints very high, but not required, priority, such as 950. That way, it will hold if it possibly can, but be broken without causing an exception if it has to be. The obvious choice is the constraint to the superview's trailing edge.

The cases where the superview is narrower than the screen are presumably when the view hierarchy is being put together, before it's shown. So, allowing the constraint to be broken at that time won't affect any actually-visible layout.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • I should probably have mentioned that this is a custom keyboard extension. Do you have any experience with that this is a common problem, or something I've caused? – Aleksander Jul 11 '15 at 20:44
  • Sorry, I don't know about that. – Ken Thomases Jul 11 '15 at 21:14
  • That's fine, I guess I'll find out at some point. For now though, lowering the priority of the constraint to the superview's trailing edge did the trick! Thanks! – Aleksander Jul 11 '15 at 22:01
1

If I'm not mistaken... It looks like you have constant width & margin constraints on your "Pasteboard" and "Last Scentence" button.

You're constraints to the side of the screen are already declaring the width. So when auto layout runs, it (understandably) doesn't know which constraint to use. So it breaks the width constraints on both your buttons and uses the other margin constraints to set the width.

Oxcug
  • 6,524
  • 2
  • 31
  • 46
  • Yes both buttons are 130 point wide, and there's a 8 point space between them as well as 8 points between the "last sentence" button and superview. However this is necessary as the buttons should always be 130 wide. It's the space between the "pasteboard" button and the globe that should go down, and then the 50 point globe button should eventually break. On the big screens however nothing should break. – Aleksander Jul 11 '15 at 20:29
  • I accidentally pressed enter on my last post. See it again for the updated comment – Aleksander Jul 11 '15 at 20:31
  • Just so I'm understanding this correctly, when the screen gets smaller in width, you'd like the two buttons to retain their 130px width and the globe to loose it's width but max out at 50px? – Oxcug Jul 11 '15 at 20:33
  • Yes the buttons should **always** be 130 wide. It's the '>=8 point' space between the blue button and the globe that should go down, and eventually break the '50 point' globe button – Aleksander Jul 11 '15 at 20:34
  • The **XIB** you see a screenshot of is 375 points wide, so running it on a 375 point wide device should not yield any errors. Increasing the size to 414 points should not either, as the >=8 point space will grow. On a 320 point wide screen, the 50 point button should break. All of this looks fine on the devices, but the errors are bothering me. – Aleksander Jul 11 '15 at 20:37
  • Ah, I see. So the two buttons should always stay right aligned and at 130pt each. However the Globe will loose it's width and margin up to 8pt? When the two 130pt buttons want that space? – Oxcug Jul 11 '15 at 20:39
  • The >=8 margin is minimum 8 points. On a 375 point wide device it'll be 41 points, on 414 even more, and on 320 just 8, but the 50 will break. I believe you are correct :) – Aleksander Jul 11 '15 at 20:40
  • @Aleksander Ah, gotcha. Gimme a few minutes to play with it then. – Oxcug Jul 11 '15 at 20:44
  • I should mention that it's a custom keyboard extension. Shouldn't have anything to say, but just in case. – Aleksander Jul 11 '15 at 20:46
  • 1
    Try setting the priority of the `>=8` constraint to 750. – Oxcug Jul 11 '15 at 20:54
  • Thank you, that did the trick! However I'm gonna have to give the **accepted answer** to user *Ken Thomases* as he was the first to suggest lowering the priority of one of the vertical constraints to something **below 1000**. He also provided an explanation as to why it had to be done. I really appreciate your answer regardless, so thank you very much! – Aleksander Jul 11 '15 at 22:00
  • @Aleksander Np. Glad you got it figured out. – Oxcug Jul 13 '15 at 16:01