Apple documentation suggests setting the height of Today Extensions using autolayout.
If a widget has additional content to display, you can rely on Auto Layout constraints to adjust the widget’s height as appropriate. If you don’t use Auto Layout, you can use the UIViewController property preferredContentSize to specify the widget’s new height.
However, every example and tutorial I have seen ends up using preferredContentSize
.
All of my attempts to set the height via autolayout lead to warnings of broken constraints.
Setting Height Via Autolayout
I started with a fresh xcode template, and a fresh today extension template. The only thing I added to the TodayViewController.m
was:
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets {
return UIEdgeInsetsMake(0, 0, 0, 0);
}
Note: I still get this problem if I just use the default margins.
I constrained the label height, centered the label in the container, and constrained the container height to be the same as the label height:
This should lead to a label that fills the container at the specified height with no constraint conflicts. Instead I get a constraint conflict:
2014-09-28 10:27:39.254 TodayExtension[61090:2672196] 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:0x7f8b8b62c670 V:[UILabel:0x7f8b8b62d9b0'Hello World'(124)]>",
"<NSLayoutConstraint:0x7f8b8b583020 UIView:0x7f8b8b62d6e0.height == UILabel:0x7f8b8b62d9b0'Hello World'.height>",
"<NSLayoutConstraint:0x7f8b8b5888a0 'UIView-Encapsulated-Layout-Height' V:[UIView:0x7f8b8b62d6e0(667)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7f8b8b62c670 V:[UILabel:0x7f8b8b62d9b0'Hello World'(124)]>
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 way that it breaks the constraints, it actually ends up looking like I want it to:
However, in other projects, it decides to break other constraints and it doesn't look correct. Also, side note: if I try and change the priority of the height constraint it crashes Xcode. So that's fun.
Not Constraining Height
I had hoped that since constraining the height didn't work, maybe if I didn't constrain the container height to the subviews, that perhaps it would figure out the required height to house the subviews and set itself correctly.
I centered the subview and constrained its height:
This just led to an extension that uses up the full height of the notification center, and my correctly sized view vertically centered:
If I don't center, but instead fix the vertical space to the top layout guide, I get the same thing except that the subview is fixed to the top (but the container is still huge).
What Gives?
I know I could just use preferredContentSize
, but then why would Apple say it can be set using Auto Layout constraints? What am I doing wrong?
The examples I have given are obviously contrived. I'm setting the height of the view, so why not just set the height of the container, right? Part of the point of this in an actual project would be to set the height of the widget based on the width using only autolayout.