6

I have observed a very strange behavior regarding Autolayout in the Today Widget I just created for my app. Trying to get to the root of the problem I ended up creating a plain new Xcode project (single view app) and added a Today Extension as a new target - without even touching it.

When I launch the Today Extension on my device (iPhone 6s) the first thing that happens is that layout constraint conflicts are thrown in the console:

2016-05-03 18:17:22.216 TodayExtension[10183:4611907] 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. 
(
    "<_UILayoutSupportConstraint:0x15c665320 V:[_UILayoutGuide:0x15c6657b0(0)]>",
    "<_UILayoutSupportConstraint:0x15c663890 V:|-(0)-[_UILayoutGuide:0x15c6657b0]   (Names: '|':UIView:0x15c6642a0 )>",
    "<_UILayoutSupportConstraint:0x15c666010 V:[_UILayoutGuide:0x15c666380(0)]>",
    "<_UILayoutSupportConstraint:0x15c666ed0 _UILayoutGuide:0x15c666380.bottom == UIView:0x15c6642a0.bottom>",
    "<NSLayoutConstraint:0x15c666b80 V:[_UILayoutGuide:0x15c6657b0]-(NSSpace(8))-[UILabel:0x15c6617c0'Hello World']>",
    "<NSLayoutConstraint:0x15c666bd0 V:[UILabel:0x15c6617c0'Hello World']-(NSSpace(8))-[_UILayoutGuide:0x15c666380]>",
    "<NSLayoutConstraint:0x15c552820 'UIView-Encapsulated-Layout-Height' V:[UIView:0x15c6642a0(0)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x15c666bd0 V:[UILabel:0x15c6617c0'Hello World']-(NSSpace(8))-[_UILayoutGuide:0x15c666380]>

You'll notice that the last one of the constraints in the list is a UIView-Encapsulated-Layout-Height which forces a height of 0 on the view. I checked and figured that the referenced view is the widget's root view itself. So for some reason that's beyond my comprehension the system internally creates a 0 pixel-height constraint that conflicts with the setup of the view in Interface Builder. (As you will see when you create a fresh today extension in Xcode there's nothing there but a a UILabel that's pinned to each side of the widget's root view.)

Normally I would claim that this is a huge iOS bug but as this is Apple's default template for creating Today Widgets I just cannot believe it's broken. Any idea what's causing this conflicting behavior and how to fix it (properly)?


What I'm basically trying to achieve with the bounty...

... is to figure out if there is a reliable way to use Autolayout in a Today Widget without introducing several workarounds and "dirty hacks" that you wouldn't use inside a normal app. (If you end up adding plenty of constraints that create fixed frames and don't let the content grow dynamically that's not really the idea of Autolayout, is it?)


Closely related question that's part of the problem and might give a hint:
Inconsistent Today Widget behavior breaks subview's height constraints

Community
  • 1
  • 1
Mischa
  • 15,816
  • 8
  • 59
  • 117
  • Did you tried adding margin by `widgetMarginInsetsForProposedMarginInsets` ? – Aadil Keshwani Jun 02 '16 at 10:11
  • Yes, I did. It's explained in the other question I linked above. – Mischa Jun 02 '16 at 11:12
  • @EICaptainv2.0: Thanks for trying to help. But first of all, if I remove the bottom constraint the Today Widget won't grow with the label's contents anymore (if you put 10 lines of text inside the label it will overlap the widget's bounds). And secondly I have successfully implemented a widget already with some dirty hacks but what I'm trying to achieve here is to find the cause for the need of these hacks and a **general solution** to properly work with Autolayout in Today widgets. One that the whole community can benefit from, that can be applied to **any** widget layout. – Mischa Jun 04 '16 at 09:57
  • @EICaptainv2.0: Thanks again for your help. It would be great however, if you didn't post comments and delete them again as soon as I've replied to them. For other users reading this page my comments will be out of context and no one will understand what's going on. – Mischa Jun 04 '16 at 10:04
  • @Mischa thats because I'll provide detail answer ... – Bhavin Bhadani Jun 04 '16 at 10:05
  • @EICaptainv2.0: You can provide an answer *and* still keep your comments. Because providing an answer won't solve the problem that the comment section here gets messy and confusing if you simply delete comments in the middle that other users responded to. – Mischa Jun 04 '16 at 10:27

2 Answers2

2

In some of Apple's stock UIView subclasses, they are instantiated with a size of zero. You need to configure your NSLayoutConstraints so that they can properly react to this initial size. In the past, I've made top or bottom constraints an inequality so that the rest of the constraints may size themselves correctly and not break the layout.

Ex: Make your bottom constraint (<NSLayoutConstraint:0x15c666bd0 V:[UILabel:0x15c6617c0'Hello World']-(NSSpace(8))-[_UILayoutGuide:0x15c666380]>) a LessThanOrEqualTo with a constant value of 8.0.

bsmith11
  • 296
  • 1
  • 3
  • When I change the bottom constraint from "Equal" to "Less Than Or Equal" the conflicts in the log disappear, yes, but then the positioning of the label is inconsistent: The first time I run the widget the "Hello World" text is vertically centered between my widget's header and the next widget's header. But when I hide the notification center and swipe it down again the text suddenly jumps up a couple of pixels and is now closer to my own widget's header. So it feels like changing the bottom constraint is only shifting the problem (bug?) to another place. – Mischa May 03 '16 at 17:20
  • 1
    You could add an additional bottom constraint `EqualTo` to `8.0` and give it a lower priority. This way it breaks when it needs to, but also forces the bottom spacing to be `8.0` when it's possible – bsmith11 May 03 '16 at 17:23
  • That in deed does the job. However, it really feels like I'm fixing a system bug here with a dirty hack. I just cannot believe that basic Autolayout (constraining a view from top to bottom) doesn't work for Apple's default today widget template! – Mischa May 03 '16 at 18:30
  • (I've experienced several more "anomalies" regarding Autolayout and the UI in general while creating my today widget and it really drives me crazy! I'd call myself "advanced" in all things Autolayout and it feels like half of the normal Autolayout rules don't apply to the today widget. Like a different set of natural laws in a parallel universe or something. See also: http://stackoverflow.com/q/37010292/2062785) – Mischa May 03 '16 at 18:37
1

The way that I've found helpful is to constrain a view on the top and the bottom, center it horizontally, and constrain the width. This has given me good results on the today widgets that I've worked on.

PaulWall43
  • 13
  • 3