我需要基于模型动态呈现 View ,因此要呈现哪个 View 和创建 View 的决定需要在 SwiftUI View 之外。这在 iOS 13 上运行良好,但在 iOS 14 上,第一个 View 再次出现而不是第二个 View ,尽管第二个 View 确实按预期进行了初始化,第一个 View 被第二次推送到导航堆栈上。
这似乎是一个 iOS 14 错误,但也许我做错了什么,所以在向 Apple 提交错误报告之前在这里询问。
这是我正在尝试做的简化版本,此代码适用于 iOS 13,但不适用于 iOS 14。
/// Defines the interface for a Screen that is presented dynamically using the Coordinator & ScreenProvider
protocol Screen {
var coordinator: Coordinator { get }
var pushNext: Bool { get set }
var sheetNext: Bool { get set }
func screenIsComplete() throws
}
/// Creates Screens on request
struct ScreenProvider {
/// Creates a Screen when receiving a `screenId` & wraps it in an AnyView
func screen(for screenId: String, coordinator: Coordinator) -> AnyView {
print("Getting screen(for screenId: \(screenId))")
switch screenId {
case "View1":
return AnyView(View1(coordinator: coordinator))
case "View2":
return AnyView(View2(coordinator: coordinator))
case "View3":
return AnyView(View3(coordinator: coordinator))
case "View4":
return AnyView(View4(coordinator: coordinator))
default:
fatalError()
}
}
}
/// What should the current Screen do after it has completed
enum ScreenPresentationAction {
case pushNext
case sheetNext
case doNothing
}
/// Determines what action should be taken after a screen has completed and serves the next Screen to the current Screen
final class Coordinator {
let screenProvider: ScreenProvider
private var screenIndex: Int = 1
init(screenProvider: ScreenProvider) {
self.screenProvider = screenProvider
}
/// What should the current Screen do after it has completed
func nextActionAfterScreenCompletion() throws -> ScreenPresentationAction {
if screenIndex < 4 {
screenIndex += 1
}
if screenIndex == 4 {
return .sheetNext
}
return .pushNext
}
/// Get the next screen to be presented
func nextScreen() -> some View {
let screenId = "View\(screenIndex)"
print("Getting nextScreen() for index \(screenIndex)")
return screenProvider.screen(for: screenId, coordinator: self)
}
}
有四个几乎相同的 View :
struct View1: View, Screen {
//------------------------------------
// MARK: Screen
//------------------------------------
var coordinator: Coordinator
@State var pushNext: Bool = false
@State var sheetNext: Bool = false
//------------------------------------
// MARK: Properties
//------------------------------------
// # Body
var body: some View {
VStack {
Spacer()
Text("View 1")
Spacer()
Button(action: {
try! self.screenIsComplete()
}) {
Text("Next")
}
Spacer()
NavigationLink(destination: self.coordinator.nextScreen(), isActive: self.$pushNext) {
EmptyView()
}
}
.sheet(isPresented: self.$sheetNext) {
self.coordinator.nextScreen()
}
}
}
extension View1 {
func screenIsComplete() throws {
let action = try coordinator.nextActionAfterScreenCompletion()
switch action {
case .pushNext:
self.pushNext = true
case .sheetNext:
self.sheetNext = true
case .doNothing:
break
}
}
}
最佳答案
您需要推迟构建导航链接目标 View (否则它会在第一次刷新时立即创建并且您会看到效果)。
使用 Xcode 12/iOS 14 测试
NavigationLink(destination: DeferView { self.coordinator.nextScreen() }, // << here !!
isActive: self.$pushNext) {
EmptyView()
}
DeferView
取自 other my solution
关于ios - 在 iOS 14 上的 SwiftUI 中显示两次 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64062153/