In this demo, you’ll create an app for visionOS using a Window mode. At the time of writing, you’ll need to use Xcode 15.1 beta, which includes visionOS 1 beta 4.
In Xcode 15.1 beta, start a New Project
from the File menu. Select the visionOS
template and choose App
from the Application pane.
Enter Vision101
as the Project Name, choose Window
in the Initial Scene
, and select None
in the Immersive Space Renderer
. You’ll add an Immersive space in a later lesson. You won’t write tests, so leave Include Tests
unchecked.
Then tap Next
and choose a place to store the app.
Look at the files in the Project Navigator
and notice Vision101App.swift
. This is a pretty standard SwiftUI app file. If you’d chosen Immersive Space Renderer or Immersive Space, you’d see them defined here. You’ll add those items later.
The rest of the app files are standard SwiftUI, except for an inclusion in Packages. Inside Packages
, you’ll find RealityKitContent
. This Swift package contains a ReadMe
, a Package.swift
manifest.
In Sources
, you’ll find RealityKitContent
containing RealityKitContent
, rkassets
, and a swift manifest. Finally, in the nested Sources
, you’ll find a Reality Composer Pro file, which you’ll use later. You don’t need the Swift Package for a Window app, but you’ll keep it for now.
Select the ContentView
file in the Project Navigator. Start the Canvas Preview
. Notice a VStack
with Model3D loading the Sphere
from the “Hello World”
text label.
In the Canvas
preview, you’ll see a living room loaded with your app window. Click and hold the fourth navigator icon and move around the space. Note the 3D Sphere is sitting in front of the window. If you have a TrackPad, you can two-finger swipe
to move around the view.
Build and run the app. Check it out in the Vision Pro Simulator.
Take a look at the controls here in the Simulator. With the Interact tool, you can use the controls in the space, open apps, enter text, or select tabs. Use the bar below the window to move it.
To resize the window, use the curved bar under the right or left corners that appear when pointing at them.
Select the Look Around tool next. You can rotate your view as if you’re pivoting on the spot.
Next is the Pan tool. Use it to move left, right, up, and down.
You previously looked at the Orbit tool, which moves you around the room.
Finally, the Dolly tool lets you move backward and forward.
Back in the ContentView
file, remove the VStack
, and add a new TabView
, with the name Window Tab, semantic font largeHeadline, and foregroundColor orange. Replace the VStack with this code:
TabView {
Text("Window Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.foregroundColor(.orange)
.tabItem {
Image(systemName: "window.awning.closed")
Text("Window")
}
}
For the tab item, open the Asset Library
, tap Symbols
, search for window awning closed, and drag it in. Add the Text window.
You created an Ornament on the side of the Window. Hover over the icon to see it shimmer and expand to show the Window title.
Add two more tabs inside the TabView to interact with:
Text("Volume Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.foregroundColor(.orange)
.tabItem {
Image(systemName: “cube”)
Text(“Volume)
}
Text("Immersive Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.foregroundColor(.orange)
.tabItem {
Image(systemName: “globe”)
Text(“Immersive”)
}
Now, add a NavigationView
in the first tab, along with a simple list:
NavigationView {
List {
Text("1st Course")
Text("2nd Course")
Text("3nd Course")
Text("4nd Course")
Text("5nd Course")
Text("6nd Course")
}
//...
}
Build and run to see the result in the Vision Pro Simulator.
Back in Xcode, change the name of ContentView
to ContentListView
.
Add a Course
struct with an ID, UUID type, and a name as a String type. Then, add some values in an array and make Course
conform to Identifiable
.
struct Course: Identifiable, Hashable {
let name: String
let id = UUID()
}
Next, declare a courses array at the top of the ContentListView
struct:
private var courses = [
Course(name: "Window App"),
Course(name: "Volume App"),
Course(name: "Immersive App"),
Course(name: "Ornaments"),
Course(name: "App Icon")
]
Replace the List
in the first tab with a List
that iterates over the new courses array:
List(courses) {
Text($0.name)
}
Add a new SwiftUI View file called CourseView
for the detail view.
Replace the contents with:
struct CourseView: View {
let course: Course
var body: some View {
VStack {
Text(course.name)
.font(.largeTitle)
}
.navigationTitle(course.name)
}
}
#Preview {
CourseView(course: Course(name: "visionOS"))
}
Notice the error Cannot find type 'Course' in scope
.
Move the Course
and ContentListView
structs out of the View
.
Add a selectedCourse
state variable:
@State private var selectedCourse: Course? = nil
Update the List
with courses, and add a NaviagtionLink
in the closure:
NavigationSplitView {
List(courses, selection: $selectedCourse) { course in
NavigationLink(course.name, value:course)
}
Add a detail value on the NavigationSplitView
:
} detail: {
if let selectedCourse = selectedCourse {
CourseView(course: selectedCourse)
} else {
Text("Select a course from the list to see its details.")
}
Course
also needs to conform to Hashable
:
struct Course: Identifiable, Hashable { //.. }
You might need to set .windowStyle(.plain)
in the app file to remove the glass background behind the whole app. Open Vision101App.swift
and add .windowStyle(.plain)
after the closing brace of WindowGroup
Make a Model
folder. Then make a new Swift Model file, Course
, and move the Course
struct into it.
Select the Views
and create a new folder to contain them.
Add content: String to Course model to hold sample content.
let content: String
Replace the Course
array with the content:
Course(name: "Window App", content: """
A volume is used to add 3D content to your app. Ut necessitatibus voluptate praesentium id eos eaque itaque cumque. Sunt error et et. Dignissimos veritatis eum ad eius omnis. Pariatur eaque nihil fuga omnis quia. Aperiam corporis odit vero aspernatur in recusandae.Delectus quo sed dolores quo architecto et necessitatibus aut. Velit impedit animi est. Sapiente animi nostrum aperiam quod ut eos. Debitis dicta voluptatem est atque. Soluta iure ipsum iure sed. Natus ut in voluptas et voluptates id
"""),
Course(name: "Volume App", content: """
A volume is used to add 3D content to your app. Ut necessitatibus voluptate praesentium id eos eaque itaque cumque. Sunt error et et. Dignissimos veritatis eum ad eius omnis. Pariatur eaque nihil fuga omnis quia. Aperiam corporis odit vero aspernatur in recusandae.Delectus quo sed dolores quo architecto et necessitatibus aut. Velit impedit animi est. Sapiente animi nostrum aperiam quod ut eos. Debitis dicta voluptatem est atque. Soluta iure ipsum iure sed. Natus ut in voluptas et voluptates id
"""),
Course(name: "Immersive App", content: """
An ImmersiveSpace takes over the view. Ut necessitatibus voluptate praesentium id eos eaque itaque cumque. Sunt error et et. Dignissimos veritatis eum ad eius omnis. Pariatur eaque nihil fuga omnis quia. Aperiam corporis odit vero aspernatur in recusandae.Delectus quo sed dolores quo architecto et necessitatibus aut. Velit impedit animi est. Sapiente animi nostrum aperiam quod ut eos. Debitis dicta voluptatem est atque. Soluta iure ipsum iure sed. Natus ut in voluptas et voluptates id
"""),
Course(name: "Ornaments", content: ""),
Course(name: "App Icon", content: "")
Add the content to CourseView
:
Text(course.content)
Spacer()
//..
}.padding(20)
Fix the CourseView
preview:
CourseView(course: Course(name: "visionOS", content: "Content"))
Build and run the app. Check out the app in the Vision Pro Simulator.
Congratulation! You made a working Window app for visionOS. Now, continue to the next part for a summary.