WWDC23 공간컴퓨팅을 위한 SwiftUI

Kyle's Archive·2023년 9월 25일

visionOS

목록 보기
1/1

Meet SwiftUI for spatial computing

WWDC23
25m
https://developer.apple.com/videos/play/wwdc2023/10109/

Introduction

  • 공간컴퓨팅을 위한 앱을 개발할 때 가장 좋은 방법은 SwiftUI를 사용하는 것이라고 소개하고 있어요.
  • 그리고 SwiftUI에만 존재하는 강력한 기능들이 있어요. UIKit으로도 개발할 수 있지만 새로운 강력한 기능들을 사용하고 빠르게 개발하기 위해서 미루었던 SwiftUI를 이제부터 적극적으로 사용해보면 좋을 것 같아요.
  • SwiftUI에 추가된 새로운 3D 기능
    - Volumes, Full spaces, 새로운 3D 제스처와 레이아웃, RealityKit의 deep integration 등등
  • 코어 빌딩블록에는 Button, Button with tooltip, Toggle, TabView, Slider, Stepper, Alert 가 있다고 하네요.
  • 홈뷰와 컨트롤 센터와 같은 코어 엘리먼츠들이 있고,
  • 친숙한 앱들에서는 TV 앱, Safari, Freeform의 3D boards, Keynote의 몰입 리허설 등이 있어요.

Button

  • MacOS / VisionOS 에서 버튼이 보이는 모습을 비교해보면 이런 차이가 있네요.
Button("Of course") { ... }
  • 모든 버튼은 호버 이펙트가 있고 아이트래킹, 손과 포인터 인풋에 반응해요.
  • 그리고 버튼을 누를 때 오디오 피드백도 있다고 하네요.

Toggle

  • Favorite 체크를 Toggle로 해보면 이렇게 보이고 레이블도 달 수 있어요.
Toggle(isOn: $favorite) {
	 Label("Favorite", systemImage: "star")
}

TabView

  • 바라보는 것만으로 탭의 레이블이 표시가 돼요.
TabView {
	DogsTab()
		.tabItem { ... }
	CatsTab()
		.tabItem { ... }
	BirdsTab()
		.tabItem { ... }
}

APIs

  • 3D 환경을 위해서 만들어진 새로운 APIs가 SwiftUI 에 포함되어 있다고 해요.
  • 이 API들은 Scene으로 부터 만들어져요.
@main
struct WorldApp: App {
	var body: some Scene {
		WindowGroup {
			ContentView()
		}
	}
}
  • WindowGroup를 이용해서 하나 또는 여러개의 윈도우를 만들 수 있어요.

Scene

  • 디스플레이에 보이는 모든 것들은 Scene으로 이루어져 있어요.

Scene의 종류

  • Window

  • Volumes

  • Full Spaces

  • 이 Scene들을 믹스하고 매치시켜 목적에 맞게 함께 사용할 수 있어요.

  • Navigation stack과 Slit view를 이용해서 계층구조처럼 디자인할 수 있어요.
  • List로 항목들을 나열할 수 있고
  • Button, Toggle, Picker를 활용하여 상호작용을 넣을 수 있어요.

Window

@main
struct WorldApp: App {
	var body: some Scene {
		WindowGroup("Hello, world") {
			TabView {
				Modules()
					.tabItem { ... }
				FunFactsTab()
					.tabItem { ... }
			}
		}
	}
}
  • TabView에는 .ornament 모디파이어를 사용할 수 있어요.

VStack(alignment: .leading) {
	 Text("Stats")
		 .font(.title)
	StatsGrid(stats: stats)
		.padding()
		.background(.regularMaterial,
			in: .rect(cornerRadius: 12))
}

Button(action: { ... }) {
	 VStack(alignment: .leading) {
		 Text(fact.title)
			 .font(.title2)
			 .lineLimit(2)

		Text(fact.details)
			.font(.body)
			.lineLimit(4)

		Text("Learn more")
			.font(.caption)
			.foregroundStyle(.secondary)
	 }
}
.buttonStyle(.funFact)

Interaction

  • Eyes
  • Hands
  • Pointer : TrackPad, Hand Gesture, Hardware Keyboard 등
  • Accessibility : Voice Over, Switch Control 등

SwfitUI gestures

SwfitUI accessibility

Hover Effect 넣기

struct FunFactButtonStyle: ButtonStyle {
	func makeBody(
		configuration: Configuration
	) -> some View {
		configuration.label
			.padding()
			.background(.regularMaterial,
				in: .rect(cornerRadius: 12))
			.hoverEffect()
	}
}

Volumes

Volumes 적용방법

  • 모디파이어를 이용하여 기본사이즈도 정할 수 있고 windowStyle.volumetric으로 바꿀 수 있어요.
@main
struct WorldApp: App {
	var body: some Scene {
		WindowGroup {
			Globe()
		}
		.windowStyle(.volumetric)
		.defaultSize(width: 600, height: 600, depth: 600)
	}
}

3D모델 띄우기

import SwiftUI
import RealityKit

struct Globe: View {
	var body: some View {
		Model3D(named: "Earth")
	}
}
  • Model3D를 사용하여 간단하게 지구를 띄어볼 수 있어요.
import SwiftUI
import RealityKit

struct Globe: View {
	var body: some View {
		ZStack(alignment: .bottom) {
			Model3D(named: "Earth")
				.rotation3DEffect(rotation, axis: .y)
				.onTapGesture {
					withAnimation(.bouncy) {
						rotation.degrees += randomRotation()
					}
				}
				.padding3D(.front, 200)
				
			GlobeControls()
				.glassBackgroundEffect(in: .capsule)
		}
	}
}
  • ZStack 을 사용하여 모델 아래에 컨트롤을 추가해줄 수 있답니다.
  • rotation을 줄 수도 있고, onTapGesturewithAnimation을 사용하여 손으로 rotation 할 수도 있어요.

RealityView

ReallityView { content in
	if let earth = try? await
		ModelEntity(name: "Earth")			 
	{
		earth.addImageBasedLigthing()
		content.add(earth)
	}
}
  • SwiftUI View에 RealityKit를 사용하면 custom material, shader, physics와 그 밖의 여러가지 것들을 추가할 수 있어요.
  • 공간경험을 위한 RealityKit의 더 자세한 내용은 아래의 세션에서 확인
    - https://developer.apple.com/videos/play/wwdc2023/10080/
@State private var pinLocation: GlobeLocation?

RealityView {
	...
} update: {
	...
	if let pin = attachments.entity(for: "pin") {
		content.add(pin)
		placePin(pin)
	}
} attachments: {
	if let pinLocation {
		GlobePin(pinLocation: pinLocation)
			.tag("pin")
	}
}
.gesture(
	SpatialTapGesture()
		.targetedToAnyEntity()
		.onEnded { value in
			pinLocation = lookUpLocation(at: value)
		}
)

Full Spaces

  • 마지막으로 가장 몰입도 높은 Scene인 Full Spaces를 살펴볼께요.
@main
struct WorldApp: App {
	var body: some Scene {
		...

		ImmersiveSpace(id: "solar-system") {
			SolarSystem()
		}
	}
}
@Environment(\.openImmersiveSpace)
private var openImmersiveSpace

Button("View Outer Space") {
	openImmersiveSpace(id: "solar-system")
}

Immersion Styles

  • Mixed : 실제나 가상환경과 함께 사용할 수 있어요.
  • Full : 전체를 몰입환경으로 만들 수 있어요
  • Progressive : 크라운 다이얼을 이용하여 몰입도를 조절할 수 있게 할 수 있어요

@main
struct WorldApp: App {
	@State private var selectedStyle: ImmersiveStyle = .full
	var body: some Scene {
		...

		ImmersiveSpace(id: "solar-system") {
			SolarSystem()
		}
		.immersiveStyle(
			selection: $selectedStyle,
			in: .full)
	}
}
struct Starfield: View {
	var body: some View {
		RealityView { content in
			let starfield = await loadStarfield()
			content.add(starfield)
		}
	}
}
struct SolarSystem: View {
	var body: some View {
		Earth()
		Sun()
		Starfield()
	}
}

ARKit

profile
Java Backend, iOS Developer (Transforming 중🤮)

0개의 댓글