[英]How can I present successive views in a SwiftUI-based iOS app?
在尝试学习 SwiftUI 时,我正在开发一个 iOS 应用程序,该应用程序显示“观察会话”的列表视图,并允许用户从“新建”按钮创建新会话。 它需要一个中间步骤来选择新的 session 将基于的配置。
我能够显示合理的 session 列表和配置列表屏幕,但我处理所选配置的尝试失败了。
发送到配置列表屏幕的闭包被成功调用,打印语句正确显示配置名称就证明了这一点。 但是应该呈现第三种视图类型的处理程序的其余部分无法工作(即它不呈现视图)。 此外,我收到一条警告,我试图展示“未使用 'sheet(isPresented:onDismiss:content:)' 的调用结果”的新视图。 我希望有人可以向我解释我做错了什么。 这是在 Xcode 12.3 中,针对模拟器中的 iOS 14。 这是显示问题的 SessionListView 代码:
import SwiftUI
struct SessionsListView: View {
@ObservedObject var dataManager: DataManager
@State private var isPresented = false
@State private var isObserving = false
var body: some View {
VStack {
List {
ForEach(dataManager.allSavedSessions) {session in
NavigationLink(
// Navigate to a detail view
destination: SessionDetailView(session: session),
label: {
Text("\(session.name)")
})
}
}
Spacer()
Button("New Session") {
isPresented = true
}
.padding()
.font(.headline)
.sheet(isPresented: $isPresented) {
// Present a configuration list view where user must select configuration to use for new session
// Requires a closure that's called upon selection in the configuration list view, to handle the selection
NavigationView {
ConfigurationsListView(dataManager: dataManager, selectionHandler: { config in
isPresented = false
isObserving = true
handleConfigSelection(config)
})
.navigationTitle("Configurations")
.navigationBarItems(trailing: Button("Cancel") {
isPresented = false
})
}
}
}
}
private func handleConfigSelection(_ config: SessionConfiguration) {
// Use the selected configuration to start an observations session
print("Selected \(config.name). Will attempt to show sheet from \(self)")
isPresented = false
isObserving = true
self.sheet(isPresented: $isObserving) { // displaying warning: "Result of call to 'sheet(isPresented:onDismiss:content:)' is unused"
NavigationView {
ObservationsView(configuration: config)
.navigationBarItems(trailing: Button(action: {}) {
Text("Done")
})
}
}
}
}
这是我在此简化演示中使用的 model 类型的代码。
观察会话:
struct ObservationSession: Identifiable {
let id: UUID = UUID()
let name: String
}
会话配置:
import Foundation
struct ObservationSession: Identifiable {
let id: UUID = UUID()
let name: String
}
数据管理器:
import Foundation
class DataManager: ObservableObject {
var allSavedSessions: [ObservationSession] {
return [ObservationSession(name: "Field mouse droppings"), ObservationSession(name: "Squirrels running up trees"), ObservationSession(name: "Squirrel behavior in urban landscapes")]
}
var allSavedConfigurations: [SessionConfiguration] {
return [SessionConfiguration(name: "Squirrel Behavior"), SessionConfiguration(name: "Squirrel/Tree Interaction"), SessionConfiguration(name: "Mouse Behavior")]
}
}
经过一夜的睡眠后,我想出了一种似乎可行的方法。
我在 SessionConfiguration 类型的 DataManager class 中添加了“currentConfiguration”属性,并在用户从列表中选择配置时在 ConfigurationsListView 中设置该属性。 然后 SessionsListView 可以显示 ConfigurationsListView 或 ObservationsView ,具体取决于跟踪流的变量:
import SwiftUI
enum SessionListPresentationFlow {
case configuration
case observation
}
struct SessionsListView: View {
@ObservedObject var dataManager: DataManager
@State private var isPresented = false
@State var flow: SessionListPresentationFlow = .configuration
var body: some View {
VStack {
List {
ForEach(dataManager.allSavedSessions) {session in
NavigationLink(
// Navigate to a detail view
destination: SessionDetailView(session: session),
label: {
Text("\(session.name)")
})
}
}
Spacer()
Button("New Session") {
isPresented = true
}
.padding()
.font(.headline)
.sheet(isPresented: $isPresented, onDismiss: {
if flow == .observation {
flow = .configuration
} else {
flow = .configuration
}
dataManager.currentConfiguration = nil
isPresented = false
}) {
// Present a view for the appropriate flow
viewForCurrentFlow()
}
}
}
@ViewBuilder private func viewForCurrentFlow() -> some View {
if flow == .configuration {
NavigationView {
ConfigurationsListView(dataManager: dataManager, selectionHandler: { config in
isPresented = false
handleConfigSelection(config)
})
.navigationTitle("Configurations")
.navigationBarItems(trailing: Button("Cancel") {
isPresented = false
flow = .observation
})
}
} else if flow == .observation, let config = dataManager.currentConfiguration {
NavigationView {
ObservationsView(configuration: config)
.navigationBarItems(leading: Button(action: {isPresented = false}) {
Text("Done")
})
}
} else {
EmptyView()
}
}
private func handleConfigSelection(_ config: SessionConfiguration) {
flow = .observation
isPresented = true
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.