UberJason
UberJason

Reputation: 3163

tvOS focus engine on a 90 degree rotated TV?

Our company is using a TV in portrait orientation hooked up to an Apple TV running our own custom app to serve as a status board. This is purely an internal, hacked-together app - no worries about sending to the App Store.

To avoid things being rendered sideways, we have a base class view controller doing a 90 degree CGAffineTransform on the view (and all other view controllers in the project inherit from this base class):

class PortraitViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.transform = CGAffineTransform(rotationAngle: -1*CGFloat.pi/2)
    }
}

This works great for showing images, text, videos, custom UI controls, etc. However, the focus engine does not rotate with the view, and because it expects the TV is still being shown in landscape orientation, the Apple TV remote gestures end up 90 degrees off from what we want. Here's an example:

enter image description here

Here, we would want swiping right/left on the remote to move the focus of the segmented control between the two segments. But because the Apple TV thinks it's being shown in landscape mode, it thinks the segmented control is oriented vertically, and swiping up/down moves the focus of the segments.

Does anyone know if there's a way to convince the focus engine not to rotate alongside the view, or alternatively, a different way to display the view in portrait mode without rotating the view?

Upvotes: 1

Views: 766

Answers (1)

Rolf Hendriks
Rolf Hendriks

Reputation: 421

This is terrible, but the only way I can think of to achieve what you want is to take over the focus system entirely. So making your root window/view focusable to hijack all input events, listening to raw input events, and managing your own focus system from raw touch/press events as needed. You can still use preferredFocusEnvironments + setNeedsFocusUpdate to leverage all system UI + animation for focusing/unfocusing elements, but would need to take full ownership of how to shift focus based on user input and how to forward focus update hints for parallax effects.

Overriding sendEvent(_ event:UIEvent) at the UIApplication or UIWindow level to transform input events into portrait coordinates before passing them on to the system seems like a great idea on paper and almost works. Except that it is impossible to generate or modify touch events programmatically. Since you are not concerned about App Store viability though maybe you can hack a way to generate or modify touch events programmatically? Subclassing UITouch/UIPress? Using performSelector to call private or undocumented methods?

Upvotes: 0

Related Questions