Search code examples
iosuitableviewcocoa-touchuikituisplitviewcontroller

Updating Table Cell Accessory when Split View Controller Collapses/Expands


In apps like the Settings app, when the UISplitViewContoller is collapsed, the UITableView cells display the standard '>' disclosure accessory icons:

Settings app in portrait orientation

On devices like the Plus-sized iPhones when rotating to landscape and the full UISplitViewController becomes visible, the disclosure icons disappear:

Settings app in landscape

When configuring the cells initially, it's possible to simply call self.splitViewController.isCollapsed to find out what the current state of the split view controller is. However when a transition occurs after that point, I'm not sure what the best way to receive notifications of that occurrence.

The easiest solution I've considered is to just call self.tableView.reloadData() inside the view controller's viewWillTransitionToSize method, but that seems like a really 'brute-force' way of doing it.

Has anyone done this sort of implementation? How did you solve it?


Solution

  • Aha! I discovered how to do it! The Apple iOS 8 sample code on size classes demonstrates how to do it.

    I was setting up my UITableViewCell instances only in the cellForRowAtIndexPath data source method, which of course, only gets called once for each cell's creation.

    Apple's sample code configures the table cell accessory view in the willDisplayCell delegate method, and this method appears to be called on each visible cell automatically when a UISplitViewController transition occurs. :)

    Edit: Okay, on further exploration, it turns out it's not automatic. It's an NSNotification.

    Here's the code from the Apple Sample app. In the view controller's viewDidLoad:

    override func viewDidLoad() {
            super.viewDidLoad()
    
            NotificationCenter.default.addObserver(self, selector: #selector(ListTableViewController.showDetailTargetDidChange(_:)), name: NSNotification.Name.UIViewControllerShowDetailTargetDidChange, object: nil)
    }
    

    And the method the notification triggers:

    func showDetailTargetDidChange(_ notification: Notification) {
        /*
            Whenever the target for showDetailViewController: changes, update all
            of our cells (to ensure they have the right accessory type).
        */
        for cell in tableView.visibleCells {
            if let indexPath = tableView.indexPath(for: cell) {
                tableView(tableView, willDisplay: cell, forRowAt: indexPath)
            }
        }
    }