iOS

Tips for Backwards Compatibility with iOS 10 Today Widgets

It’s been really interesting seeing how prominence for today widgets have changed over the past couple of years. First introduced in iOS 8, today widgets weren’t given a very high place of honor and were coupled with missed notifications within Notification Center. However, in iOS 10, emphasis on today widgets has drastically changed, completely taking over the swipe-left option on the home screen that used to belong to “Slide to unlock.” They also received quite the transformation in terms of their appearance going from a dark theme to a pearly white now.

Unfortunately for developers, if you’re like my team and can’t drop support for iOS versions below 10 quite yet, you have to figure out how to best support both styles of appearance, as well as a few other things that aren’t obvious at first glance. I recently went through this transformation with the QuickBooks Self-Employed today widget – here’re some things to watch out for:

Supporting Both Themes

iOS 9 today widget
iOS 9 today widget
iOS 10 today widget
iOS 10 today widget

 

 

 

 

 

 

 

Let’s start with the obvious one. You’ll either need to build two different interfaces for versions lower than iOS 10 as well as iOS 10+, or make sure that a single interface is compatible with both dark and light backgrounds. We ended up solving this by building one interface, but displaying light and dark text and background colors for our view elements depending on which version of iOS we were on. We also made sure that any image assets or colored text looked good on both backgrounds. Modifying the image tint color proved to be useful here.

//Swift
var image = UIImage(named: "imageName");
image = image?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
let imageView = UIImageView(image: image)
imageView.tintColor = UIColor.blue
//Objective-C
UIImage *image = [UIImage imageNamed:@"imageName"];
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.tintColor = [UIColor blueColor];

Centering Widget

Off-center iOS 9 widget

Now here’s one thing that’s not so obvious – the slight center offset of iOS 9 today widgets. If you notice on the image above, you can see that the UITableView above is not centered horizontally in the middle of its space. Unless you feel like making slight adjustments for your iOS 9 today widget, I’d suggest setting the margins so that they allow you to use the entire width of the allocated space, matching what is default in iOS 10.

//Swift
func widgetMarginInsets(forProposedMarginInsets defaultMarginInsets: UIEdgeInsets) -> UIEdgeInsets {
    return UIEdgeInsetsMake(0,0,0,0);
}
//Objective-C
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets {
    //centers widget for iOS 9
    return UIEdgeInsetsMake(0,0,0,0);
}

Note: widgetMarginInsetsForProposedMarginInsets is technically deprecated and will not get called on versions iOS 10 and above.

Lost Features in Expanded Mode

Compact mode
Compact mode
Expanded Mode
Expanded mode

 

 

 

 

 

 

iOS 10 added an optional expanded mode to add additional functionality and real estate to widgets. This is super useful in the case of power user features or something that the user might not want to show on their home screen all the time (e.g. personal or financial information). You can set this using this line of code in your viewDidLoad:

//Swift
self.extensionContext?.widgetLargestAvailableDisplayMode = NCWidgetDisplayMode.expanded
//Objective-C
self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;

However, this basically breaks your extension in iOS 9, so you’ll actually need to wrap it to make sure it’s only set if modifying the display mode is supported.

//Swift
let extensionContext = NSExtensionContext()
if #available(iOS 10.0, *) {
    extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayMode.expanded
}
//Objective-C
if ([self.extensionContext respondsToSelector:@selector(setWidgetLargestAvailableDisplayMode:)]) {
    self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
}

One more thing to consider with expanded mode is that anything that only shows in expanded mode (beyond 110 px) is cut off in iOS 9 or below if you don’t set the height of your widget properly. To do this, you’ll need to make sure you set the height for the preferredContentSize of the widget so that it includes any content you have beyond 110 px. Thanks to Greg Gardner for pointing this out!

2 thoughts on “Tips for Backwards Compatibility with iOS 10 Today Widgets

  1. I have found that if the user sets the font to a different size (in Accessibility) the initial state of the widget in iOS10 is not always right, and it’s not 110px. When expanding collapsing the widget, the size will adjust and be slightly different from it’s initial size.

  2. I second what Chris writes but want to add that the size doesn’t differ “slightly”. For really big fonts the size can be up to twice as big as “normally”
    It can also be smaller. For small font sizes.
    So using a fixed height for the widget actually doesn’t work.

Leave a Reply