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!