Code Repo: github.com/xuchi16/vis...
Project Path: github.com/xuchi16/vis...
在 窗口,空间容器和空间 中我们了解了如何在 visionOS 中打开新的窗口。但在默认的实现中,无论是最初的导航窗口还是后续打开的新窗口,它们的大小和位置未必满足需求。
为了控制窗口的位置和尺寸,需要通过 modifier 控制初始的窗口位置。
二维窗口(Window)
初始情况
初始 visionOS 项目页面如下,有一个ContentView
,其中包含了一个 3D 的模型和一个按钮。并在 App 中,定义了一个WindowGroup
来渲染ContentView
。在 visionOS 中,默认会打开 App 类中定义的第一个 Scene,这里就是ContentView
。
swift
// PositionAndSizeApp.swift
@main
struct PositionAndSizeApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
这时,窗口的行为:
- 初始状态:打开的面积太大
- 缩放行为:可以任意缩放,太大了内容偏小,太小了会裁切(clipping)掉部分内容
理解概念
首先需要先理解 View 和 Window 的关系,
View: A type that represents part of your app's user interface.
Windows: Display user interface content in a window or a collection of windows.
-
View:应用中的一组 UI 元素构成一个视图,可以嵌套,是构建整个应用的基础
-
Windows:是一个窗口,用来容纳 View。包括 Window 和 WindowGroup。其中 visionOS 并不支持 Window,而只支持 WindowGroup。
直观地举个例子,如果在 WindowGroup 中定义 2 个 View,则实际展示会变成一个窗口里堆叠了 2 个同样的 View。
swift
// PositionAndSizeApp.swift
@main
struct PositionAndSizeApp: App {
var body: some Scene {
WindowGroup {
ContentView()
ContentView() // Duplicate the previous view
}
}
}
控制大小
初始大小
这里我们需要控制的是 Window 而非 View,因此通过 Window 的.defaultSize
modifier 即可指定大小。
swift
@main
struct PositionAndSizeApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.defaultSize(CGSize(width: 800, height: 600))
}
}
缩放行为
控制缩放则是通过 2 个步骤的配合来完成的
- 控制 View 的 frame 大小
- 控制 Window 的缩放类型,即
.windowResizability
其中,.windowResizability
提供了 3 种类型
- automatic:不控制,这也是默认的控制类型
- contentSize:根据窗口中的内容决定缩放大小
- contentMinSize:根据窗口中的内容部分控制,只控制缩放到最小的情况,不控制放大
swift
@main
struct PositionAndSizeApp: App {
private var defaultWidth = 800.0
private var defaultHeight = 600.0
private var expandRatio = 1.6
private var shrinkRatio = 0.8
var body: some Scene {
WindowGroup {
ContentView()
.frame(
minWidth: defaultWidth * shrinkRatio, maxWidth: defaultWidth * expandRatio,
minHeight: defaultHeight * shrinkRatio, maxHeight: defaultHeight * expandRatio)
}
.windowResizability(.contentSize)
.defaultSize(CGSize(width: defaultWidth, height: 600))
ImmersiveSpace(id: "ImmersiveSpace") {
ImmersiveView()
}
}
}
这里我们通过上述两步,即可以达到如下效果:
- 初始状态:按照设定大小打开
- 缩放行为 :有最大和最小边界
空间容器(Volume)
当我们在初始窗口中打开一个新的 Volume 窗口时,会发现
- 位置:默认出现的位置
- 大小:尽管 3D 模型很小,但默认的 Volume 窗口很大,控制器离物体很远
类似于 2D 窗口,也可以通过.defaultSize
modifier 控制空间容器窗口的大小。
默认情况
指定初始大小
指定位置
You can't use
defaultPosition(_:)
in visionOS. The system always places new windows directly in front of people, where they happen to be looking at the moment the window opens. This helps to make people aware of new windows.
在 macOS 中,可以通过defaultPosition(_:)
来控制窗口打开时的位置,如打开在页面底部。但 visionOS 中,窗口总是在用户面前打开,从而让用户意识到了有新的窗口,因此并不支持指定打开位置。