Instruction 2
Adapting UI
Using a ScrollView quickly fixed the problem, and users of RGB Picker can now enjoy the app in landscape. And yet, something still feels off. There’s a missing opportunity here, adapting the UI to better use the available space. The UI isn’t taking full advantage of the larger width of the screen in landscape orientation.
That’s because SwiftUI is still applying the same vertical layout, no matter the orientation. Its still using a VStack to arrange its subviews and build the UI. And while this works great in portrait orientation, it’s not a good solution when the user rotates the device. In landscape orientation, you can fit so much more on screen with a horizontal layout.
That happens because the iPhone has more height than width when in portrait orientation. But when you rotate the device to landscape, the story completely changes. The width of the screen is way bigger than the height, making use of VStack to layout all those elements oddly in this orientation.
The title is way up at the top of the ScrollView and there’s no way to scroll the view so that you can see the full size of the rectangle and sliders at the same time.
The Importance of Using the Right Layout
VStack and HStack are used to build the most common UI. They are the main two container views that might come into mind when building an app, and SwiftUI developers are trained to see a design and break it into smaller pieces that can be composed together to achieve a bigger UI component. VStack and HStack will get the job done with most UI ideas.
When you start thinking about landscape orientation and accessibility, just using one or the other might not be enough. You start to run into issues like the ones you just saw where the UI ends up being out of screen or not like the original design you had intended.
And while using a ScrollView is a valid solution, it may not always be the best solution.
A better use of the new available width space would be to swap VStack for a HStack, where the title and color rectangle would be on the left, and the sliders and button on the right. This balances out the UI in a nice way so that the user no longer has to scroll through the content to see all the elements on screen. Everything fits nicely.
Understanding Device Size Classes
This is where device size classes comes into play. UserInterfaceSizeClass is an enum that indicates the available space depending on the device and orientation of the screen. It can be either .compact or .regular.
Those values are found in the environment of views, by reading the horizontalSizeClass and verticalSizeClass environment values, and use them to change the layout and behavior of views.
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Environment(\.verticalSizeClass) var verticalSizeClass
On the iPhone 15 Pro on portrait orientation, horizontalSizeClass is .compact and verticalSizeClass is .regular. In other words, on portrait, the device has more space on the vertical axis than the horizontal axis. On landscape orientation, the values change a bit; horizontalSizeClass is .compact and verticalSizeClass is also .compact. That’s because even though the iPhone has more width space in landscape orientation, it still may be limited, so you still have to be aware of how much content to fit on the screen.
This is true for most iPhones. However, the iPhone 15 Plus and iPhone 15 Pro Max are different. They have big enough screens that when in landscape, horizontalSizeClass is .regular allowing you to use layouts that are more appropriate for bigger devices.
And SwiftUI also uses this to change the behavior of some of its native views. For example, a NavigationSplitView displays multiple columns when the horizontal size class is .regular. That’s because the amount of available width on screen is bigger, meaning it has more space for NavigationSplitView to display a navigation column and the content of the view.
This is true on iPad and on the iPhone Pro 15 Max, when in landscape orientation.
But on smaller devices, NavigationSplitView uses a list and navigation to handle this, since there’s not enough horizontal space to display two columns.
iPadOS and Multitasking
On iPadOS, you also use Device size classes to adapt the UI of your app depending on the status of multitasking. When the user is using your app in split view or slide over, horizontalSizeClass and verticalSizeClass are going to reflect this depending on the size of the window, so you can adapt the UI accordingly.
You’ll use these values to determine how much space you have available and in which context, orientation and device the view is, and adapt the UI of RGB Picker to better suit the new available space.