SwiftUIPanoramaViewer
是一个高性能库,它使用 SceneKit 来显示完整的球形或圆柱形全景图,并支持触摸、游戏手柄或基于运动的控制,可在 SwiftUI 项目中使用。
SwiftUIPanoramaViewer
基于 scihant's 的 CTPanoramaView 开源库的源代码,我对其进行了大量修改,以支持现代 OSes、SwiftUI、读取 Pitch & Yaw、支持 游戏手柄 以及更多功能。
为什么要创建一个新的库? 我发布
SwiftUIPanoramaViewer
作为一个新的库/包,而不是在CTPanoramaView
上提交 pull request,原因有几个,但主要原因是以下两个:首先,看起来CTPanoramaView
不再被支持。 其次,我所做的 SwiftUI 更改使得CTPanoramaView
偏离了其支持UIKit
和 Objective-C 的原始设计。
因此,您将在软件包中找到我的 MIT 许可证,以及 scihant's 的原始 MIT 许可证,该许可证来自 CTPanoramaView
开源库。
如果您发现 SwiftUIPanoramaViewer
有用,并希望帮助支持其持续开发和维护,请考虑进行少量捐赠,尤其是在您将其用于商业产品时
正是通过像您这样的贡献者的支持,我才能继续构建、发布和维护高质量、文档完善的 Swift 包,例如免费的 SwiftUIPanoramaViewer
。
使用 Xcode 的 Swift Package Manager
https://github.com/Appracatappra/SwiftUIPanoramaViewer.git
粘贴到对话框中。为什么不选择 CocoaPods、Carthage 等?
支持多个依赖项管理器会使维护库的复杂性和耗时呈指数级增长。
由于 Swift Package Manager 与 Xcode 集成,因此它是最容易支持的进一步选择。
SwiftUIPanoramaViewer
提供了一种简单的方法,可以将交互式球形或圆柱形全景查看器添加到任何 SwiftUI View
。 让我们看下面的例子
@State var rotationIndicator:Float = 0.0
...
ZStack {
// Display the panorama
PanoramaViewer(image: SwiftUIPanoramaViewer.bindImage("PanoramaImageName")) {key in }
cameraMoved: { pitch, yaw, roll in
rotationIndicator = yaw
}
VStack {
Spacer()
CompassView()
.frame(width: 50.0, height: 50.0)
.rotationEffect(Angle(degrees: Double(rotationIndicator)))
}
}
// If using `SwiftUIGamepad` package, allow the gamepad to rotate the view.
.onGamepadLeftThumbstick(viewID: viewID) { xAxis, yAxis in
PanoramaManager.moveCamera(xAxis: xAxis, yAxis: yAxis)
}
让我们分解一下关键点
rotationIndicator
- 我们创建了一个 State 变量来跟踪全景图旋转的变化。PanoramaViewer
- 这会显示带有默认用户交互的全景图,即在移动设备上触摸。SwiftUIPanoramaViewer.bindImage("PanoramaImageName")
- 辅助函数 SwiftUIPanoramaViewer.bindImage
返回给定名称的绑定 UIImage
。 此图像应该是保存在应用程序的资源目录中的球形或圆柱形全景图,或者通过 按需资源 下载的全景图。cameraMoved
- 当用户与全景图交互并移动视图时,将调用 cameraMoved
事件。 在这里,我们将 yaw(或 X 轴移动)存储在 rotationIndicator
变量中以更新指南针。CompassView()
- 在全景图底部显示一个指南针覆盖层,指示用户正在观看的方向。rotationEffect
- 我们在 CompassView
上使用 rotationEffect
以及 rotationIndicator
变量,以将指南针指向用户在全景图中“观看”的方向。如果想将全景图像存储在 按需资源 中,请参阅我们的 ODRManager Package,以帮助您更轻松地使用 ODR。
在其当前实现中,一次只能在您的应用程序中激活一个
PanoramaViewer
。 您可以使用PanoramaManager
单例类与当前活动的查看器通信。
通过在您的 SwiftUI 应用程序中包含我们的 SwiftUIGamepad Package,可以轻松地将游戏手柄支持添加到 PanoramaViewer
。 以下代码行允许连接的游戏手柄的左拇指杆移动全景视图
// If using `SwiftUIGamepad` package, allow the gamepad to rotate the view.
.onGamepadLeftThumbstick(viewID: viewID) { xAxis, yAxis in
PanoramaManager.moveCamera(xAxis: xAxis, yAxis: yAxis)
}
使用 PanoramaManager.moveCamera
传达全景视图中 xAxis
(或 yaw)和 yAxis
(或 pitch)的变化量。 cameraMoved
事件将在 PanoramaViewer
上响应此更改而引发。
在 SwiftUI
View
中使用SwiftUIGamepad
需要比此处显示的更多设置。 为了简洁起见,仅显示了SwiftUIPanoramaViewer
的特定部分。 有关所需的完整设置,请参阅SwiftUIGamepad
DocC 文档。
通过创建您自己的存储类并记录给定全景图像中的特定 pitch
和 yaw
点,您可以创建 Indicators 或 Interaction Points,这些点可以响应 cameraMoved
事件而显示。
如果返回到 cameraMoved
事件的 pitch
和 yaw
点与结构中的特定点匹配,只需使用 ZStack
显示覆盖在 PanoramaViewer
上的 Icon 或 Button。
PanoramaManager
单例类提供了几个辅助函数来协助完成此任务
leadingTarget
- 计算给定命中目标 (yaw, pitch) 的 左上角。trailingTarget
- 计算给定命中目标 (yaw, pitch) 的 右下角。targetHit
- 给定来自 PanoramaViewer
的当前 pitch
和 yaw
,检查它是否在给定的目标点内。inRange
- 测试给定的旋转点,以查看它是否在指定的范围内。由于可以在 SwiftUI 应用程序中使用
PanoramaViewer
的所有不同方式,因此提供所有数据结构以支持交互和节点导航超出了此库的范围。 任何“默认”实现对于任何给定应用程序的需求来说都可能过于局限或过于复杂。因此,我决定提供易于实现此功能的工具,同时将具体细节留给消费应用程序的代码。
如果您需要由于用户交互(或任何其他应用程序内事件)而更改 PanoramaViewer
中显示的全景图像,则需要执行一些额外的步骤。 请参阅以下代码片段
@State var panoImage:String = "MyImage"
...
PanoramaViewer(image: SwiftUIPanoramaViewer.bindImage(panoImage))
...
// Change the displayed image
PanoramaManager.shouldUpdateImage = true
PanoramaManager.shouldResetCameraAngle = false
panoImage = "newPanoImage"
在此代码中,我们使用 State 变量 panoImage
来保存当前显示的全景图像。 以下是关键点
PanoramaManager.shouldUpdateImage
- 通过将此属性设置为 true
,您是在通知 PanoramaViewer
它需要查找即将发生的图像更改。 这允许查看器进行必要的内务管理,以确保图像平滑更改,而不会在 UI 中出现不必要的闪烁。PanoramaManager.shouldResetCameraAngle
- 通过将此属性设置为 false
,我们告诉 PanoramaViewer
在图像更改时保持当前的 pitch
和 yaw
。 如果此属性为 true
,则当图像更改时,pitch
和 yaw
都将重置为零 (0)。panoImage
- 当我们指定一个新图像时,PanoramaViewer
将进行更改,并将 PanoramaManager.shouldUpdateImage
属性重置为 false
。更改
PanoramaViewer
中显示的全景图像的请求应在主线程上执行以获得最佳效果。
Package 包括其所有功能的完整 DocC Documentation。