Implementing the expanded view

The expanded view for the iMessage app will be a table view that lists all of the quotes in the Quote struct. You will use a similar setup to the one you used before by creating a new view controller file and using the delegate protocol to communicate the selection of a quote back to MessagesViewController.

First, create a new UITableViewController subclass and name it QuotesTableViewController. You can remove most of the commented template code; the only methods you should keep are tableView(_:cellForRowAt:), tableView(_:numberOfRowsInSection:), and numberOfSections(in:). In addition to the commented delegate methods, you can remove the viewDidLoad() and didReceiveMemoryWarning() methods; you don't need them.

For starters, you should implement the methods shown in the following code snippet. These methods provide the table view with its data:

override func numberOfSections(in tableView: UITableView) → Int {
  return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) → Int {
  return Quote.numberOfQuotes
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) → UITableViewCell {
  let cell = tableView.dequeueReusableCell(withIdentifier: "QuoteTableViewCell", for: indexPath)
  let quote = Quote.quote(atIndex: indexPath.row)

  cell.textLabel?.text = quote?.text
  cell.detailTextLabel?.text = quote?.creator
  return cell
}

The preceding snippet uses a numberOfQuotes property on the Quote struct. However, this property is not defined yet. Add it to the Quote struct, as shown in the following code snippet:

static var numberOfQuotes: Int { return quotes.count }

The last thing you should take care of before creating and connecting the interface is the quote-selection delegate and implementing cell selection in QuotesTableViewController. The code to do this is pretty straightforward:

var delegate: QuoteSelectionDelegate?

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  guard let quote = Quote.quote(atIndex: indexPath.row)
    else { return }
  delegate?.shareQuote(quote)
}

This leaves you with a complete implementation of the table view in code. Let's create the interface in Interface Builder. Open MainInterface.storyboard and drag out a table view controller. Assign QuotesTableViewController as its class and Storyboard ID. Also, click the prototype cell and set its style to Subtitle. The Identifier for the cell should be set to QuoteTableViewCell. That's all you need to do for now. Let's make sure that you display this view controller when the iMessage app is in the expanded presentation mode.

In MessagesViewController, update willBecomeActive(with:) so it can display both the expanded and compact mode as the initial view, depending on presentationStyle:

override func willBecomeActive(with conversation: MSConversation) {
  if self.presentationStyle == .compact {
    showCompactView()
  } else if self.presentationStyle == .expanded {
    showExpandedView()
  }
}

Since the user can manually change the display mode for the iMessage app, you will need to dynamically switch the view controller that is shown depending on the presentation style. Add the following implementation for willTransition(to:):

override func willTransition(to presentationStyle: MSMessagesAppPresentationStyle) {
  if presentationStyle == .compact {
    showCompactView()
  } else if presentationStyle == .expanded {
    showExpandedView()
  }
}

Finally, you should take care of showing the correct view. You should always make sure to remove any existing view controllers before you show a new one. showExpandedView() has not been implemented yet, but if you think about what this method should do for a second, you will realize it should look very similar to the showCompactView() method. It's a good idea to implement a special cleanup method and refactor showCompactView(), so you can reuse it for showExpandedView(). First, add the following method that will be used to clean up the displayed view controllers when needed:

func cleanupChildViewControllers() {
  for viewController in children {
    viewController.willMove(toParent: nil)
    viewController.removeFromParent()
    viewController.didMove(toParent: nil)

    viewController.view.removeFromSuperview()
  }
}

One last thing that needs to be done before implementing the presentation of the expanded view controller is adding a property for this expanded view controller in MessagesViewController and updating viewDidLoad(), so it creates a new instance of QuotesTableViewController that will be used as the expanded view controller. Add the following property and the viewDidLoad() implementation to MessagesViewController:

var expandedViewController: QuotesTableViewController?

override func viewDidLoad() {
  super.viewDidLoad()

  compactViewController = storyboard?.instantiateViewController(withIdentifier: "CompactViewController") as? CompactViewController
  compactViewController?.delegate = self

  expandedViewController = storyboard?.instantiateViewController(withIdentifier: "QuotesTableViewController") as? QuotesTableViewController
  expandedViewController?.delegate = self
}

Next, let's implement the refactored view controller presentation methods:

func showCompactView() {
  guard let compactViewController = self.compactViewController
    else { return }

  showViewController(compactViewController)
}

func showExpandedView() {
  guard let expandedViewController = self.expandedViewController
    else { return }

  showViewController(expandedViewController)
}

func showViewController(_ viewController: UIViewController) {
  cleanupChildViewControllers()

  viewController.willMove(toParent: self)
  addChild(viewController)
  viewController.didMove(toParent: self)

  view.addSubview(viewController.view)
  viewController.view.frame = view.frame
}

After doing this, build and run the app to see your extension in action. It flawlessly switches between showing the list of quotes and the single daily quote.

The final step in implementing our iMessage app is to implement the shareQuote(_:) method. This method will compose a message that can be shared. Let's have a look at message composition and everything related to it.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset