How do you force a view controller to call preferredFocusView?

So I have a view controller that has the following methods:

    var viewToFocus: UIView? = nil {
        didSet {
            if viewToFocus != nil {
                self.setNeedsFocusUpdate()
                self.updateFocusIfNeeded()
            }
        }
    }

    override weak var preferredFocusedView: UIView? {
        if viewToFocus != nil {
            let theView = viewToFocus
            viewToFocus = nil
            return theView
        } else {
            return super.preferredFocusedView;
        }
    }

So essentially I can force a focus update to the view I want by setting viewToFocus to a value, which works great in most cases. However, when removing a subview this doesn't seem to work properly and preferredFocusedView is never called.

In terms of my subview, it's an overlay that covers the screen (don't ask why I didn't use a modal, there were reasons for that) and has the parent view controller as a delegate. The parent view controller has the following methods:

// Delegate of 'OverlayView'. Called BEFORE it is added as a subview
func beforeOpeningOverlay() {
    focusedViewBeforeOverlay = UIScreen.mainScreen().focusedView
}

// Delegate of 'OverlayView'. Called after its close action is triggered.
func closedOverlay(overlay: OverlayView) {
    if focusedViewBeforeOverlay != nil {
        viewToFocus = focusedViewBeforeOverlay
        focusedViewBeforeOverlay = nil
    }
    overlay.delegate = nil
    overlay.removeFromSuperview()
}

For some reason when closedOverlay is called, and focusedViewBeforeOverlay has a valid non-nil view, it is never the next view focused on after the overlay is removed from the superview. Like I said preferredFocusedView is never called, and focus instead focuses on whatever the focus engine decides should be the next focus.

Anyone know why that might be the case? Does removing a subview not allow you to trigger a focus update?

So the order, or at least expected order, should be:

  1. Something triggers OverlayView to be instantiated
  2. beforeOpeningOverlay() is called, and the currently focused view is set to focusedViewBeforeOverlay. The overlay is then opened and captures focus
  3. Something triggers the overlay view to close, calling closedOverlay()
  4. viewToFocus = focusedViewBeforeOverlay line is called
  5. A focus update should be called for the parent viewcontroller, calling its preferredFocusedView
  6. preferredFocusedView should return viewToFocus which was set to focusedViewBeforeOverlay and revert focus back to the view that was focused before the overlay opens

The issue seems to be that step 5 and onwards aren't called

Upvotes: 0

Views: 3434

Answers (1)

As Roman commented, referredFocusedView was deprecated in tvOS 10. Now you have to define your preferredFocusEnvironments.

That in your case would be something like:

override var preferredFocusEnvironments: [UIFocusEnvironment] {
    if let focusEnviroment = self.viewToFocus { return [focusEnviroment] }
    return super.preferredFocusEnvironments
}

You also need to call self.setNeedsFocusUpdate() for updating the focus.

Upvotes: 2

Related Questions