Discover how you can bring your multiplatform SwiftUI app to visionOS and the Shared Space. We'll show you how to add the visionOS destination to an existing app and view your app in the Simulator. Explore how your SwiftUI code automatically adapts to support the unique context and presentation of the visionOS platform. Learn how you can update custom views, improve your app's UI, and add features and controls specific to this platform.
♪ Mellow instrumental hip-hop ♪ ♪ Hello! I'm Harlan, and I work on SwiftUI. I'm thrilled to help you make your windowed app truly spectacular on this new spatial platform. With spatial computing, your apps exist within your physical surroundings, which enables whole new classes of stunning three-dimensional experiences.
And as with every Apple platform, the best way to build an app is with SwiftUI. SwiftUI has added a suite of APIs and behaviors that take advantage of everything this new platform has to offer. If you haven't already, watch "Meet SwiftUI for spatial computing" for an overview of all the new ways you can use SwiftUI on this device. I'll be focusing on SwiftUI but if you're working with UIKit, there's a lot you can take advantage of too. Check out "Meet UIKit for spatial computing" to learn how to make the best UIKit experience possible. If you have an existing iPhone or iPad app and you'd prefer to retain your iOS experience, check out "Run your iPad and iPhone apps in the Shared Space." Whether you're bringing an app from another Apple platform or making something brand-new, SwiftUI is the best way to make your app feel at home wherever it runs. In this session, we'll update a SwiftUI app for this platform. We'll begin by exploring how the built-in controls automatically adapt themselves for legibility and interaction; we'll talk about how to ensure your custom views and controls take advantage of the new visuals and input techniques on this device; and we'll adopt some brand-new features that are only possible with this device. This platform was built from the ground up with SwiftUI in mind. In fact, most of the system applications are written with SwiftUI, like Keynote, Freeform, and TV, which all bring their familiar interfaces right into your surroundings. Even though these apps look similar to their iPad counterparts, they take full advantage of the new design language and interaction methods on this platform. Let's explore how you can do the same with your apps by updating an iPad app together. This is Backyard Birds, and it's like a virtual birdwatching app, where you can feed and record all the birds that visit your yard. As a Swift developer, I love birds. This is my kind of app. Backyard Birds is written in SwiftUI. It's a great example of a multiplatform SwiftUI app. It supports iPhone, iPad, Mac, and Apple Watch. I'd like to add one more platform to that list. Let's make Backyard Birds really sing in the Shared Space. First, make sure your app supports this new platform by adding it in the Supported Platforms menu in Xcode.
This will add a new run destination, so let's choose that and run our app in the simulator.
Here in the simulator, when I move my cursor around, the app responds as if I was looking around with my eyes. When we run Backyard Birds, we immediately find that it has the same basic layout as on iPad, but some things appear a little different. The first difference I notice is that the app now has a glass background. Glass is a standard background provided to windows by default. It adjusts its contrast and color balance based on lighting conditions and the colors of objects behind it. Because of that, this platform does not make a distinction between light and dark appearances. Glass automatically ensures your app stays legible no matter where you're using it. Let's explore Backyard Birds some more. Backyard Birds has a navigation split view at the top level, which provides this sidebar for switching between top-level views. The sidebar automatically darkens its background on top of glass to visually separate itself from the detail view. When I hover the cursor over these list rows, they highlight subtly. I can tap on these rows to switch between views, just like on iPad. On the right side of the split view is a navigation stack. When I tap on one of the backyards, it navigates to its details view. From here I can see how much seed and water is left for the birds in this yard. I can scroll down to see a list of all the birds that have recently visited. The navigation bar has these circular buttons that also highlight when I look at them. When I press the Favorite button, it scales down and then toggles the favorited state. These are just a few of the things that SwiftUI has done to enhance every app for the Shared Space. Now that we've taken a stroll around Backyard Birds and found some of the new, automatic behaviors that the built-in controls offer, let's investigate how we can make our custom views and controls feel at home. I spotted something subtle while we toured the Backyards list. If I get really close to the app, the bird and plants remain crisp, but the fountain becomes a little blurry. I suspect the fountain is being drawn at a fixed resolution. Apps on this device are placed in your physical surroundings. And unlike other platforms, there's no screen with physical pixels that defines the quality at which your content can draw. Apps could be positioned anywhere. They might be pushed far away from you, or brought right up close, or even viewed at an angle. The system ensures that apps look great in all these situations by scaling content dynamically. For the system to do that, you must provide vector assets because bitmaps cannot be scaled without reducing quality. Text and SF Symbols are already vectors, but if you're using custom icons or graphics, use vectors to take advantage of dynamic content scaling. Let's check if that fountain is a bitmap image. Ah, if I look at the scales option, it's specified in individual scales. Thankfully, I have a vector for this asset already, so I'll switch it to a single scale, remove the existing assets, and replace it with my vector. Then I'll check the Preserve Vector Data box, which allows the contents to scale to any size. This setting is supported on all Apple platforms. That's better. Now the fountain is sharp, and if I move closer or further away, it stays at high quality. Let's poke around some of the other tabs. The Plants tab shows a grid of all the plants, and these circles behind the plants look bright and out of place. If we inspect the code, we find our answer: the background is a solid color. Solid colors like this one have a fixed contrast against glass and can't adjust to your surroundings. There's a check here to use a slightly darker color in Dark Mode, which is a common practice on iOS. This platform reports its color scheme as dark, so this is the color we see behind the plants. But remember, this platform doesn't distinguish between light and dark color schemes. Instead, the best way to make sure your content is legible, regardless of what's coming through glass, is to adopt vibrancy. Vibrant materials introduce additional contrast and brightness to ensure that content on top of glass remains legible no matter what's shining through. All of the built-in controls and containers use these vibrant materials by default, so if you're using standard controls, there's no extra work for you here. SwiftUI's semantic styles automatically adopt an appropriate appearance on each platform. On this device, they look vibrant when placed on top of glass. If you're building your own custom views or containers, use these semantic styles to make your content legible no matter how glass adapts to your surroundings. Let's change these plant icons to use a semantic fill color rather than a solid color. Since we're using semantic materials, we can remove the color scheme check altogether. Now the code is simpler and more correct on all platforms. Wow, these icons are much better. They pop beautifully against the glass in every lighting condition. Now that we've spent some time improving the visuals in the app, let's make sure all the interactive components are clear and easy to target. As you learned in "Meet SwiftUI for spatial computing," there are four ways you can interact with your apps. The most common interaction is an indirect pinch gesture, where you look at a control and pinch your fingers together to perform a tap. If an app is close to you, you can directly interact with it just by reaching out and touching it. If you've paired a trackpad, you can use it as a pointer for precise input. And the world-class accessibility technologies that you're already familiar with on Apple platforms are also available on this device. Tools like VoiceOver and Switch Control enable everyone to have the same great experience using your apps. On this platform, interactable content is highlighted using hover effects. For example, when you look at a control like a button or a list, a subtle highlight effect over the view's bounds makes it clear that you can interact with it. These hover effects are crucial to making your app feel responsive. They give people confidence that the view they're looking at or reaching for is the view that they'll interact with. Hover effects are added automatically to all system controls. If you use the built-in controls provided by SwiftUI, you'll get these effects in your app for free. I noticed a missing hover effect on the Birds tab of our app. I can tap on one of these birds, but there's no visual indication that I can do that because there's no hover effect. Whenever you make a control that responds to gestures like taps, it should probably have a hover effect. You can add one using the hoverEffect() modifier. By default, the hover effect is a highlight, meaning it will brighten when you look at the control. With our new hover effect, it's clear that I can interact with these controls, but the hover effect has these sharp corners, and I think they'd look a little better rounded. I can provide a custom shape using the contentShape() modifier, with hoverEffect as the kind. The hoverEffect() modifier reads this content shape out of the view that it modifies.
There, that feels much better. The hover effect is clear and has a bit of padding and nice rounded corners. However, I think there's more that we can do. In SwiftUI, if a control performs an action in response to a tap, it's likely that the control should just be a button. Let's change the bird view to a button.
Buttons are bordered by default on this platform, but I don't want these buttons to have a background when I'm not looking at them. I'll make this a plain button, so it gets a standard hover effect but no background or internal padding. Perfect! These buttons have a standard hover effect, and they scale down when they're tapped. Hover effects were built to preserve privacy. These effects are performed by the system outside of your app's process. System hover effects are the only way to make your app react to where people are looking. Your app is only told when someone pinches their fingers, directly touches your app, or hovers their finger or pointer over your controls. After all these changes, I'd say Backyard Birds is looking pretty good. But by making some small changes to our layout and adopting some features unique to this platform, we can really take to the skies. Let's talk about some of the top-level layout. On iPad, when a window's horizontal size class is regular, a sidebar is preferred over a tab view because it makes better use of the increased width. On this device, however, your windows are not tied to the size of a screen, and controls are not required to live inside your window. Consider using a tab view to switch between top-level views. When using a tab view, the tab bar is attached to the left side of your app, like the one here in Photos. When you look at one of the icons, it automatically expands to show each tab's label. Let's go ahead and switch from a navigation split view to a tab view. I'll make a view for each screen in the app... ...and give it a tab item with a title and icon. Nice! The tab bar is collapsed when you're not interacting with it, and the app now has much more room for its content. Notice how the tab bar sits outside of the window instead of within it. This kind of attachment is called an ornament. Ornaments are positioned outside the boundaries at the edges of your windows and are a great place to put additional controls that you want alongside your main content. In addition to the tab bar, Photos has a toolbar at the bottom that lets you control the time ranges shown in your library. These kinds of ornaments are so common, you can add one automatically with the .toolbar modifier using the bottomOrnament placement. Toolbar ornaments provide a glass capsule background automatically. I have an idea for an ornament to add to Backyard Birds. I try to keep an eye on how much water and seed I've left out, but if I'm running low, I'd like to be told that a feeder needs a refill. You can build this kind of custom ornament using the ornament() modifier. The attachmentAnchor determines where in your app the ornament will be attached. I could put my notification on any edge of my app window, but I want to align it to the bottom. The contentAlignment parameter lets you choose what part of your ornament is aligned to the attachmentAnchor. I'd like to put the center of my ornament at the bottom of my app. Because you have more control over the contents of a custom ornament, SwiftUI does not give them a glass background by default. If you do want one, you can use the .glassBackgroundEffect() modifier on the ornament's contents. Now when there's not enough water or seeds in any of my yards, I'll get this message at the bottom of my app, and I can tap on it to navigate to that yard. I love it! Because SwiftUI automatically adapts to the platform it's running on, it was simple to make Backyard Birds feel at home in the Shared Space. You can follow the same steps in your apps. Add hover effects to interactive controls, use vector assets and vibrancy for legibility, and make ornaments for auxiliary controls. There's still so much more that you can explore that's only possible on this platform, like volumes for 3D content and Immersive Spaces for spatial experiences. Check out "Take SwiftUI to the next dimension" and "Go beyond the window with SwiftUI" to learn how to expand your app beyond its window. Thanks and happy coding! ♪
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.