
App extensions in the Today view are called widgets. Widgets give users quick access to information that’s important right now. For example, users open the Today view to check current stock prices or weather conditions, see today’s schedule, or perform a quick task such as marking an item as done. Users tend to open the Today view frequently, and they expect the information they’re interested in to be instantly available.
The best widgets give users quick updates or enable very simple tasks. If you want to create an app extension that enables a multistep task or helps users perform a lengthy task, such as uploading or downloading content, the Today extension point is not the right choice.
Because user interaction with Today widgets is quick and limited, you should design a simple, streamlined UI that highlights the information users are interested in. In general, it’s a good idea to limit the number of interactive items in a widget. In particular, note that iOS widgets don’t support keyboard entry.
Below is a tutorial that implements a Time Widget to display clocks for a couple of time zones. This fits into the Apple requirement of making it a simple dynamic task that users may need frequently without wanting to open a full app.
Setup the Application Extension
- Select File > New > Project. Select the Single view application template, and call it TodayWidget.
- Add the Application Extension Target. Select File > New > Target…. Then in the left pane, select Application extension and under that choose Today Extension. Because our Today extension is going to show times, give it the name TimeWidget.
- A message will popup asking if you want to activate the “TimeWidget” scheme. Click Cancel. We will debug it using the normal Application scheme.
Create the Today Widget View
Today widgets are just like any other view within your application and built using a UIViewController. Next we’ll create our view for what will appear in the widget.
- In the project navigator, expand TimeWidget group and click on MainInterface.storyboard.
- Select the “Hello World” label already there and delete it.
- Click on the “View” and open the Size Inspector and change the height of the view to 60.
- Drag a eight UILabels into the view, the top four be the titles of the time zones and the bottom four will be clocks. See the image below.
- Define your IBOutlet label variables within the “TodayViewController.swift” and add in the perferredContentSize of the view so it will display the correct height in the Today View.
// // TodayViewController.swift // TimeWidget // // Created by Brian Coleman on 2014-10-16. // Copyright (c) 2014 Brian Coleman. All rights reserved. // import UIKit import NotificationCenter class TodayViewController: UIViewController, NCWidgetProviding { @IBOutlet var pacificLabel: UILabel! @IBOutlet var mountainLabel: UILabel! @IBOutlet var centralLabel: UILabel! @IBOutlet var easternLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view from its nib. self.preferredContentSize = CGSizeMake(320, 50); } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)!) { // Perform any setup necessary in order to update the view. // If an error is encountered, use NCUpdateResult.Failed // If there's no update required, use NCUpdateResult.NoData // If there's an update, use NCUpdateResult.NewData completionHandler(NCUpdateResult.NewData) } }
- Connect the IBOutlets to the new variables within the MainInterface.storyboard.
Test Your Today Widget
- When you run the app you’ll see a blank view since our app doesn’t do anything except create the Today Widget.
- Drag from the top of your view down to display the notification center. Next tap the “Edit” button.
- Tap the green plus button next to the TimeWidget. You’ll see it got added below the Calendar. Drag it to re-order it so it shows above the Calendar.
- Tap “Done” and you should see our TimeWidget displayed in the Today Widget view.
Add in Live Dynamic Data
We are almost done making our widget, let’s add in the clocks to finish it up.
import UIKit import NotificationCenter class TodayViewController: UIViewController, NCWidgetProviding { @IBOutlet var pacificLabel: UILabel! @IBOutlet var mountainLabel: UILabel! @IBOutlet var centralLabel: UILabel! @IBOutlet var easternLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view from its nib. self.preferredContentSize = CGSizeMake(320, 50); self.updateClocks() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)!) { // Perform any setup necessary in order to update the view. // If an error is encountered, use NCUpdateResult.Failed // If there's no update required, use NCUpdateResult.NoData // If there's an update, use NCUpdateResult.NewData completionHandler(NCUpdateResult.NewData) } func updateClocks() { var time: NSDate = NSDate() println("Time: \(time)") var timeString : NSString = "Time: \(time)" let formatter:NSDateFormatter = NSDateFormatter(); var timeZone = NSTimeZone(name: "UTC") formatter.timeZone = timeZone formatter.dateFormat = "HH:mm" println("UTC Time: \(formatter.stringFromDate(time))") timeZone = NSTimeZone(name: "US/Eastern") formatter.timeZone = timeZone formatter.dateFormat = "HH:mm" println("EST Time: \(formatter.stringFromDate(time))") easternLabel.text = formatter.stringFromDate(time) timeZone = NSTimeZone(name: "US/Pacific") formatter.timeZone = timeZone formatter.dateFormat = "HH:mm" println("PST Time: \(formatter.stringFromDate(time))") pacificLabel.text = formatter.stringFromDate(time) timeZone = NSTimeZone(name: "US/Mountain") formatter.timeZone = timeZone formatter.dateFormat = "HH:mm" println("MT Time: \(formatter.stringFromDate(time))") mountainLabel.text = formatter.stringFromDate(time) timeZone = NSTimeZone(name: "US/Central") formatter.timeZone = timeZone formatter.dateFormat = "HH:mm" centralLabel.text = formatter.stringFromDate(time) } }
You can grab the full source code for this tutorial. Note: Built for Xcode 6.0.