视频通过solar system 这个项目讲解SwiftUI 在visionOS的入门操作。
构建空间app需要使用swiftUI,苹果扩展了swiftUi功能,并能和RealityKit深度配合。
从Windows、Volumes、Full Spaces三个方面介绍swiftUI实现的一些例子。
Button("Of course") {
// perform action
}
Toggle(isOn: $favorite) {
Label("Favorite", systemImage: "star")
}
TabView {
DogsTab()
.tabItem {
Label("Dogs", systemImage: "pawprint")
}
CatsTab()
.tabItem {
Label("Cats", image: "cat")
}
BirdsTab()
.tabItem {
Label("Birds", systemImage: "bird")
}
}
通过上面代码简单介绍visionOS 上demo的基本按钮、点击效果和简单tab。通过上面例子可以看出用swiftUI在visionOS 上很简单。
- windows
简单代码示例:
@main
struct WorldApp: App {
var body: some Scene {
WindowGroup("Hello, world") {
ContentView()
}
}
}
每个window类似原来app 的是一个视图
在window上可以使用类似原来app的导航结构和类似iPad 上app的左右分组。还可以使用左测list来对内容分组导航。
— Ornaments
window 外的view成为“装饰”
visonOS 没有light 和dark模式了,原有Material来决定。、
如下面代码 regularMaterial
VStack(alignment: .leading, spacing: 12) {
Text("Stats")
.font(.title)
StatsGrid(stats: stats)
.padding()
.background(.regularMaterial, in: .rect(cornerRadius: 12))
}
在交互模式上,可以使用眼睛、手势还有Pointer、Accessibility。系统还支持外接键盘。
swiftiUi 还支持一些新手势交互。
swiftiUI accessibility 也适配了visionOS
例如Dwell control 只能使用眼神。
悬停效果
代码示例: FunFactButtonStyle 中的hoverEffect
Button(action: {
// perform button action
}) {
VStack(alignment: .leading, spacing: 12) {
Text(fact.title)
.font(.title2)
.lineLimit(2)
Text(fact.details)
.font(.body)
.lineLimit(4)
Text("Learn more")
.font(.caption)
.foregroundStyle(.secondary)
}
.frame(width: 180, alignment: .leading)
}
.buttonStyle(.funFact)
struct FunFactButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding()
.background(.regularMaterial, in: .rect(cornerRadius: 12))
.hoverEffect()
.scaleEffect(configuration.isPressed ? 0.95 : 1)
}
}
针对vison app 需要添加装饰和悬停效果
- Volumes
Volumes 代码创建示例
@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")
}
}
有些类似加载图片
3d 对象相关控制代码
struct Globe: View {
@State var rotation = Angle.zero
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)
}
}
func randomRotation() -> Double {
Double.random(in: 360...720)
}
}
RealityView 引入示例
通过RealityView 引入可以使用RealityView丰富的api
RealityView { content in
if let earth = try? await
ModelEntity(named: "Earth")
{
earth.addImageBasedLighting()
content.add(earth)
}
}
苹果建议在SiwiftUI Views 使用realityKit。可以加入丰富的阴影、物理等行为。
通过SpatialTapGesture 给reality View 加手势
struct Earth: View {
@State private var pinLocation: GlobeLocation?
var body: some View {
RealityView { content in
if let earth = try? await
ModelEntity(named: "Earth")
{
earth.addImageBasedLighting()
content.add(earth)
}
}
.gesture(
SpatialTapGesture()
.targetedToAnyEntity()
.onEnded { value in
withAnimation(.bouncy) {
rotation.degrees += randomRotation()
animatingRotation = true
} completion: {
animatingRotation = false
}
pinLocation = lookUpLocation(at: value)
}
)
}
}
加attachments
struct Earth: View {
@State private var pinLocation: GlobeLocation?
var body: some View {
RealityView { content in
if let earth = try? await
ModelEntity(named: "Earth")
{
earth.addImageBasedLighting()
content.add(earth)
}
} update: { content, attachments in
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
withAnimation(.bouncy) {
rotation.degrees += randomRotation()
animatingRotation = true
} completion: {
animatingRotation = false
}
pinLocation = lookUpLocation(at: value)
}
)
}
}
- Full Spaces
full spaces设置
@main
struct WorldApp: App {
var body: some Scene {
// (other WindowGroup scenes)
ImmersiveSpace(id: "solar-system") {
SolarSystem()
}
}
}
添加button
@Environment(\.openImmersiveSpace)
private var openImmersiveSpace
Button("View Outer Space") {
openImmersiveSpace(id: "solar-system")
}
通过RealityView 加一个星空背景
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 可以带来更多体验