Search code examples
swiftuisplitviewcontrollertvosapple-tv

UISplitViewController on tvOS - Disable Swipe to Detail View Controller


Been digging through the documentation but I can't seem to find a way to accomplish the following.

My SplitViewController loads with a UITableView as the master, however I can simply swipe the Apple TV remote to the right to get to the Detail View. How can I disable this gesture so that I can make it so the detail view is only enabled once a selection is made in the master view?

From the docs, var presentsWithGesture: Bool sounds like the right thing to do but that is only for views that are already hidden. My views are displayed side by side and both are visible. Any ideas?


Solution

  • You can create a property on your master view controller to keep track if you want focus in the detail view controller or not, like:

    var presentDetail = false
    

    Then you should override shouldUpdateFocusInContext to not allow focus updates heading to the right.

        override func shouldUpdateFocusInContext(context: UIFocusUpdateContext) -> Bool {
            if context.focusHeading == .Right { return false }
            return super.shouldUpdateFocusInContext(context)
        }
    

    Next you need to override the preferredFocusedView:

    override var preferredFocusedView: UIView?{
        if self.presentDetail {
            self.presentDetail = false
            guard let vc = self.splitViewController?.viewControllers[1] else { return nil }
            return vc.view
        }
        return self.tableView
    }
    

    Normally we'll return our tableView but when we want to shift focus to the detail view controller we'll return its view.

    Lastly we implement didSelectRowAtIndexPath:

        override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
            if let vc = self.splitViewController?.viewControllers[1] {
                self.presentDetail = true
    
                self.setNeedsFocusUpdate()
                self.updateFocusIfNeeded()
    
                vc.setNeedsFocusUpdate()
                vc.updateFocusIfNeeded()
            }
        }
    

    Where we request updates to the focus engine on our master view controller and detail view controller.