Bokeh

Making sense of the mess in my head

Interface orientation in visionOS

Introduction

Yesterday, during the super interesting Unwrap Live 2024 stream on visionOS from Paul Hudson, I asked the question on whether it was possible to have your visionOS start in “portrait mode”.

The reason I asked is because I’m extending a small utility app (AWG Convert) that I’ve coded on the iPhone to have native support for the Vision Pro. There is no iPad version (for now), and the iPhone version only supports portrait orientation. So my first idea was to port “as is” to Vision Pro. And I was thinking people can just have a small vertical window arranged on the side of other windows in their environment.

The answer Paul gave was that Apple made it clear that humans have more scope from left to right than up and down and so it makes much more sense to go wide than tall.

That makes a lot of sense and checking information on human field of view (FOV), although you can find varying information, usually indicates that humans of about 200° of horizontal FOV (both eyes combined) and 135° of vertical FOV.

Being stubborn

Let’s say I still wanted to go ahead and have my app start with a vertical window.

The article Positioning and sizing windows | Apple Developer Documentation gives the key to it and leads to the following code

WindowGroup {
	ContentView()
}
.defaultSize(width: 400, height: 700)

But this does not prevent the user from resizing the window to a wide aspect ratio. The following code would achieve this

WindowGroup {
	ContentView()
		.frame(minWidth: 300, maxWidth: 500, minHeight: 600, maxHeight: 800)
		.background(.red)
}
.windowResizability(.contentSize)

but let’s face it, this is fighting the system and will lead to an alien app in the Apple ecosystem.

Playing nice

The app should adapt to whatever window size and aspect ratio the user chooses.

How would you achieve this?

Under iOS, it’s possible to check for the device orientation and adapt to it (some information on how to do it in How to detect device rotation - a free SwiftUI by Example tutorial).

But under visionOS, UIDevice.current.orientation is unavailable. Of course, the device orientation doesn’t make sense for the Vision Pro.

Anyway, this is not the recommended way to adapt your UI layout, as e.g. on the iPad, with multitasking, your device can by in landscape orientation but your UI canvas be in portrait.

I believe the recommended way to address this, is by checking the reported size classes and adapting the layout based on that.

But testing this on the Vision Pro simulator always reports a size class of regular for both horizontal and vertical directions, irrelevant of the window size or aspect ratio. So that will not help.

For now, the solution I’ll be testing further is to use GeometryReader to get the size available for my interface and adapt accordingly (even though GeometryReader comes with its shortcomings too).

Trying it out yourself

I created a small projet to test out device orientation, size classes and GeometryReader information as reported under different platforms, it’s available on GitHub for you to test it out: Test_DeviceOrientation