Code Repo: github.com/xuchi16/vis...
Project Path: github.com/xuchi16/vis...
基本概念
装饰物(ornament)利用了 visionOS 无边画布的特性,将与特定窗口相关的功能组合成小工具条,通过悬浮的形式呈现在窗口周围。它不会占据窗口空间,也不会影响窗口展现的内容。
我们比较容易将其与 Tab bar、Tool bar 等混淆。实际上 ornament 指的是 visionOS 中特有的这种将小工具条悬浮展现在窗口上的形式,它可以是:
-
系统组件:如 Tab bar,通常展示在窗口左侧,用于导航;Tool bar,通常悬浮在底部,用来放置常用工具
-
自定义控件:如音乐、视频播放器,根据需求提供不同的功能,可以放在不同的位置,通常在底部
由于 ornament 附着在一个窗口上,因此它会与关联的窗口一同移动。相对于窗口,ornament 的位置在 z 轴上会有一定偏移,同时在 y 轴方向会有一定重叠,从而体现两者的关联性。
在外观设计方面
-
通常 ornament 总是可见的,这样用户操作更方便
-
Ornament 的宽度不超过其所关联的窗口,否则可能影响到其他窗口
-
Ornament 中的按钮不需要边框,用户注视按钮时系统会自动提供注视、点击动效
-
常用的功能使用系统自定的 Tab bar 或 Tool bar 即可,必要情况下才自定义
基本实现
最基本的 ornament 实现如下:
swift
struct ContentView: View {
var body: some View {
Text("A view with an ornament")
.ornament(
visibility: .visible,
attachmentAnchor: .scene(.bottom)
) {
OrnamentControl()
}
}
}
OrnamentControl
控制 ornament 中对应的交互控件。
swift
struct OrnamentControl: View {
@State var isPencilOn = true
@State var isEraserOn = false
var body: some View {
VStack() {
HStack {
Toggle(isOn: $isPencilOn) {
Label("Pencil", systemImage: "pencil")
}
.help("Pencil")
.padding(12)
Toggle(isOn: $isEraserOn) {
Label("Eraser", systemImage: "eraser")
}
.help("Eraser")
.padding(12)
}
.glassBackgroundEffect(in: .rect(cornerRadius: 50))
.toggleStyle(.button)
.buttonStyle(.borderless)
.labelStyle(.iconOnly)
}
}
}
实现效果如下:
我们还可以通过 4 个参数进一步控制 ornament:
-
visibility
:控制是否可见,根据设计推荐应该总是可见的 -
attachmentAnchor
:控制附着在窗口的位置,一共有 9 个位置可选 -
contentAlignment
:控制窗口与 ornament 如何对齐 -
content
:Ornament 中需要展示的内容
通过attachmentAlignment
控制不同位置效果如下:
.topLeading | .top | .topTrailing |
---|---|---|
.leading | .center | .trailing |
.bottomLeading | .bottom | .bottomTrailing |
上表中,可以发现如.leading
位置的效果很别扭。如果想达到与类似原生 Tab bar 在左侧的展示类似,则可以
- 将 ornament 放置在窗口左侧,
- 使用 trailing 对齐,从而与窗口分开
- 将图标使用 VStack 竖向排列
这样设置后效果如下。但正如上文提到的设计推荐原则,通常使用系统自定的 Tab bar 或 Tool bar 即可,只有在自定义的情况下才需要自己通过 ornament 实现功能及外观。