I would like to tell a little bit about how to create a simple Today Widget for iOS 8 and higher. We can find a lot of application in the store with widgets, really different widgets, such as weather, currencies, quick buttons for tracking something, location, etc. Example from my application, which displays currencies:
It’s not separated application, which you can submit to the store, it’s extension of your application, and you can’t submit only the widget.
Let’s start. First of all, add a new target to your project:
Choose options:
And create a scheme:
Now you have MainInterface.storyboard and TodayViewController.swift. The main controller implements NCWidgetProviding protocol. In this protocol we have two methods:
// If implemented, the system will call at opportune times for the widget to update its state, both when the Notification Center is visible as well as in the background.
// An implementation is required to enable background updates.
// It’s expected that the widget will perform the work to update asynchronously and off the main thread as much as possible.
// Widgets should call the argument block when the work is complete, passing the appropriate ‘NCUpdateResult’.
// Widgets should NOT block returning from ‘viewWillAppear:’ on the results of this operation.
// Instead, widgets should load cached state in ‘viewWillAppear:’ in order to match the state of the view from the last ‘viewWillDisappear:’, then transition smoothly to the new data when it arrives.
@available(iOS 8.0, *)
optional public func widgetPerformUpdateWithCompletionHandler(completionHandler: (NCUpdateResult) -> Void)
// Widgets wishing to customize the default margin insets can return their preferred values.
// Widgets that choose not to implement this method will receive the default margin insets.
optional public func widgetMarginInsetsForProposedMarginInsets(defaultMarginInsets: UIEdgeInsets) -> UIEdgeInsets
In the first method you need to fetch a new data if you have, and you need to call a completion handler with three possible values: NewData, NoData, Failed. And widget will be know, will update UI or use old snapshot.
In the second method Apple gives a chance to change margins. By default Today Widget has left margin, you can see in default Apple applications, such as Calendar, Stocks.
For example:
func widgetMarginInsetsForProposedMarginInsets(defaultMarginInsets: UIEdgeInsets) -> (UIEdgeInsets) {
return UIEdgeInsetsZero
}
Let’s create a simple extension. Please, add the TableView to interface and set up an outlet.
For the static height of the view you need to set up preferredContentSize:
self.preferredContentSize.height = 200
Implementation of loading data, for example from plist:
func loadData() {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
self.data.removeAll()
if let path = NSBundle.mainBundle().pathForResource(“Data”, ofType: “plist”) {
if let array = NSArray(contentsOfFile: path) {
for item in array {
self.data.append(item as! NSDictionary)
}
}
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
And of course the simple implementation of UITableView:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("tableViewCellIdentifier", forIndexPath: indexPath)
let item = data[indexPath.row]
cell.textLabel?.text = item["title"] as? String
cell.textLabel?.textColor = UIColor.whiteColor()
return cell
}
And finally we get the result:
Full code you can find in this repository. Happy coding!