SwiftUI Navigation Stack — 如何进行深度链接以及新增功能
SwiftUI Navigation Stack — 如何进行深度链接以及新增功能
iOS Developers when seeing the new Navigation Stack on WWDC2022
你好呀!这正是我在今年 WWDC 上宣布新的 Navigation Stack 时所说的,我对此非常高兴。我快乐的基础是我确切地知道我将用它做什么!
就在我的脑海里,我有一个想法:Deeplinks 导航终于!从那天起,因为我没有时间做,但时间到了,这将是我关于 Medium 的第一篇文章,并开始介绍 iOS16 中所有新的 SwiftUI 功能的系列文章。所以让我们开始派对吧!
好的,但发生了什么变化? 对于不熟悉该主题的人,我将快速浏览一下以前版本的 SwiftUI 中导航和深度链接的外观。因此,在我们作为开发人员使用 NavigationView 和 NavigationLink 之前,这将使我们能够在应用程序中导航用户,它看起来像这样:
结构特征:可识别、可散列、可解码{
var id: String = UUID().uuidString
让标题:字符串
让描述:字符串
让类型:FeatureType
} 枚举 FeatureType:字符串,可解码 {
案例图表
箱规
} 最终类 ContentViewModel: ObservableObject {
@Published var selectedFeature:功能?
@Published var showFeatureScreen: Bool = false
@ViewBuilder func showFeature() -> 一些视图 {
如果让特征 = selectedFeature {
开关功能。类型{
案例.charts:
ChartsScreen(功能:功能)
案例.gauge:
GaugeScreen(特征:特征)
}
}
}
} 结构内容视图:查看{
@StateObject var viewModel = ContentViewModel()
var body: 一些视图 {
导航视图 {
ZStack {
NavigationLink(isActive: $viewModel.showFeatureScreen) {
viewModel.showFeature()
} 标签: {}
滚动视图 {
LazyVStack(间距:8){
ForEach(viewModel.features) { 特征
FeatureCell(特征:特征){
viewModel.selectedFeature = 特征
viewModel.showFeatureScreen = true
}
}
}
}
.navigationTitle("iOS16 功能")
.onOpenURL { 网址在
print(" \(url)")
守卫让组件= URLComponents(url:url,resolvingAgainstBaseURL:true)else { return }
让查询 = components.queryItems ?? []
让主机 = components.host
让方案 = components.scheme
如果方案==“showdownRouting”&&主机==“功能”{
var jsonQuery = query.map { "\"\($0.name)\":\"\($0.value ?? "")\"" }.joined(分隔符: ",")
jsonQuery = "{\(jsonQuery)}"
守卫让 jsonData = jsonQuery.data(使用: .utf8) else {
返回
}
做 {
让特征 = 尝试 JSONDecoder.shared.decode(Feature.self, from: jsonData)
viewModel.selectedFeature = 特征
viewModel.showFeatureScreen = true
} 抓住 {
打印(错误)
}
}
}
}
}
}
}
这是您以旧方式处理简单深层链接的方式,正如您所看到的,这种方法的问题是一次只能打开一个屏幕,从长远来看这很麻烦。然后,当您在树中打开一些导航时,您将面临缺少 pop-to-root 方法的问题。并且您需要使与导航树相关的所有绑定无效。
好吧,这个有问题 但是我们能用它做什么呢?导航栈!
新的 导航栈 和 导航路径 UIKit 开发人员会非常熟悉,他们会喜欢这样:
枚举 FeatureType:字符串,可解码 {
案例图表
箱规
}
结构特征:可识别、可散列、可解码{
var id: String = UUID().uuidString
让标题:字符串
让描述:字符串
让类型:FeatureType
}
最终类 ContentViewModel: ObservableObject {
@Published var navigationPath = NavigationPath()
var 特征:[特征] = [
Feature(title: "图表",
description: "使用图表在 SwiftUI 视图中构建富有表现力和动态的数据可视化。",
类型:.charts),
特征(标题:“仪表”,
description: "SwiftUI 引入了一个名为 Gauge 的新视图来显示进度。在最基本的形式中,仪表的默认范围是 0 到 1。",
类型:.gauge)
]
**func showFeature(_ feature: Feature) {
navigationPath.append(功能)
}**
}
结构内容视图:查看{
@StateObject var viewModel = ContentViewModel()
var body: 一些视图 {
NavigationStack(路径:$viewModel.navigationPath){
滚动视图 {
LazyVStack(间距:8){
ForEach(viewModel.features) { 特征
FeatureCell(特征:特征){
viewModel.showFeature(特征)
}
}
**.navigationDestination(for: Feature.self) { 特征在
开关功能。类型{
案例.charts:
ChartsScreen(功能:功能)
案例.gauge:
GaugeScreen(特征:特征)
}
}**
.navigationTitle("iOS16 功能")
}
.onOpenURL { 网址在
print(" \(url)")
守卫让组件= URLComponents(url:url,resolvingAgainstBaseURL:true)else { return }
让查询 = components.queryItems ?? []
让主机 = components.host
让方案 = components.scheme
如果方案==“showdownRouting”&&主机==“功能”{
var jsonQuery = query.map { "\"\($0.name)\":\"\($0.value ?? "")\"" }.joined(分隔符: ",")
jsonQuery = "{\(jsonQuery)}"
守卫让 jsonData = jsonQuery.data(使用: .utf8) else {
返回
}
做 {
让特征 = 尝试 JSONDecoder.shared.decode(Feature.self, from: jsonData)
viewModel.showFeature(特征)
} 抓住 {
打印(错误)
}
}
}
}
}
}
}
如您所见,我们将 NavigatonPath 对象保留在 ViewModel 中,我们可以向其推送各种数据,例如 Feature,然后对其做出反应,在这种情况下,为了简单起见,我只检查它是什么类型。这种方法非常适合 SwiftUI,同时专注于建模数据和状态。
这使我们能够向堆栈添加更多内容,并通过将 navigationPath 向下传递到我们在 NavigationPath 上推送的视图来轻松弹出堆栈的根:
.navigationDestination(for: Feature.self) { 特征在
开关功能。类型{
案例.charts:
**ChartsScreen(功能:功能,导航路径:$viewModel.navigationPath)**
案例.gauge:
GaugeScreen(特征:特征)
}
} // 图表屏幕实现:
结构图表屏幕:查看{
var 特征:特征
@Binding var navigationPath: NavigationPath
@StateObject var viewModel = ChartsViewModel()
var body: 一些视图 {
堆栈{
文本(特征.描述)
.font(.footnote)
。填充()
.multilineTextAlignment(.center)
.onTapGesture {
**navigationPath.removeLast(navigationPath.count)**
}
间隔()
堆栈{
按钮 {
带动画{
viewModel.team = viewModel.team.sorted { $0.seniority < $1.seniority }
}
} 标签: {
文本(“排序”)
.foregroundColor(.white)
。填充()
.background(.green)
.cornerRadius(10)
}
按钮 {
带动画{
viewModel.team = viewModel.team.shuffled()
}
} 标签: {
文本(“随机播放”)
.foregroundColor(.white)
。填充()
.background(.red)
.cornerRadius(10)
}
}
滚动视图 {
条形图
折线图
面积图
}
}
.navigationTitle(功能。标题)
.navigationBarTitleDisplayMode(.inline)
}
这是效果:
正如你所看到的,实现非常简单,我很高兴我们将能够在不久的将来使用它,而新 iPhone 即将问世!
所有源代码都是公开的,并将在该系列的下一集中更新有关新功能的内容。
[
iOS-16-MacOS-13-SwiftUI-Showdown 下载iOS-16-MacOS-13-SwiftUI-Showdown的源码_GitHub_帮酷
新的 SwiftUI 4 具有适用于 iOS16+ 的示例应用程序。为 LSWarss/iOS-16-macOS-13-SwiftUI-Showdown 的开发做出贡献...
github.com
](https://github.com/LSWarss/iOS-16-MacOS-13-SwiftUI-Showdown)
如果您对接下来会发生什么等感到好奇,请在 GitHub 上关注它。感谢您的阅读,我很好奇您是否喜欢这种形式的文章。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明