visionOS: An Introduction

Nov 21 2023 · Swift 5.9, visionOS 1.0 beta, Xcode 15

Lesson 01: Getting Started with visionOS

Demo

Episode complete

Play next episode

Next
Transcript

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.

See forum comments
Cinema mode Download course materials from Github
Previous: visionOS Simulators Next: Conclusion