Currently, I am experimenting on a Vision Pro app as a side project. One thing I was not aware of for quite some time was this new paradigm with the fancy name Ornaments only used on visionOS. I just happily added buttons near the bottom edge of my view. However, using an ornament is the way to go. It is basically a kind of elevated group of controls at the bottom of the view. You can read more on it in Apple’s Human Interface Guidelines (HIG): https://developer.apple.com/design/human-interface-guidelines/ornaments/
Using new SwiftUI features
If you want to learn about other new SwiftUI features you can use for making your visionOS app feeling “more home”, please checkout my other article:
https://mic.st/blog/develop-and-release-a-visionos-app-without-vision-pro/
How to implement ornaments
When I first tried implementing my ornament, it just did not work. And I could not really find any useful information on why it did not work. What I found out about after sleeping over it: Your scene must not be of window style must not be .volumetric
it has to be .automatic
(or plain). If it’s your initial screen also make sure to set UIWindowSceneSessionRoleApplication
for the key UIApplicationPreferredDefaultSceneSessionRole
inside of your info.plist.
This means your info.plist should have this content:
<dict>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UISceneConfigurations</key>
<dict/>
<key>UIApplicationPreferredDefaultSceneSessionRole</key>
<string>UIWindowSceneSessionRoleApplication</string>
</dict>
</dict>
Code language: HTML, XML (xml)
And your initial WindowGroup
should look similar to this (so you can still set the view’s bounds if you want):
WindowGroup(id: someIDIfNeeded) {
MyFunkyView()
}
.windowStyle(.automatic) // or .plain
.defaultSize(Size3D(width: 1.8, height: 1, depth: 0.1), in: .meters)
Code language: Swift (swift)
The following won’t work. Or at least the ornament will not be shown:
WindowGroup(id: someIDIfNeeded) {
MyFunkyView()
}
.windowStyle(.volumetric)
.defaultSize(Size3D(width: 1.8, height: 1, depth: 0.1), in: .meters)
Code language: Swift (swift)
As soon as you have this set up, you can just use the .ornaments
modifier e.g. on your NavigationStack
like this:
.ornament(visibility: .visible, attachmentAnchor: .scene(.bottom), contentAlignment: .center) {
HStack(spacing: 16) {
Text("HELLO ORNAMENT 🚀")
Button {
print("Tapped that!")
} label: {
Label("Big Button", systemImage: "hare")
.padding(16)
}
}
.font(.extraLargeTitle)
.padding(32)
.glassBackgroundEffect()
}
Code language: Swift (swift)
Eventually, this is how the ornament above will look like:
Conclusion
If your ornament is not show, make sure you are showing it on an WindowGroup
using .plain
window style. Otherwise, it is just not shown for some reason.
Happy Coding! 🚀