ios - 在 iOS 14 上的 SwiftUI 中显示两次视图
问题描述
我需要基于模型动态呈现视图,因此要呈现哪个视图和创建视图的决定需要在 SwiftUI 视图之外。这在 iOS 13 上运行良好,但在 iOS 14 上,第一个视图再次出现而不是第二个视图,尽管第二个视图确实按预期进行了初始化,第一个视图被第二次推送到导航堆栈上。
这似乎是一个 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)
}
}
有四个几乎相同的视图:
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
}
}
}
解决方案
您需要推迟构建导航链接目标视图(否则它会在第一次刷新时立即创建并且您会看到效果)。
使用 Xcode 12 / iOS 14 测试
NavigationLink(destination: DeferView { self.coordinator.nextScreen() }, // << here !!
isActive: self.$pushNext) {
EmptyView()
}
DeferView
取自我的其他解决方案
推荐阅读
- r - 需要根据总数重新排序情节
- solr - SAP Hybris 布尔自定义方面
- javascript - 无法从 package.json 中的 https://json.schemastore.org/ 加载架构
- python - json.decoder.JSONDecodeError:预期值:第 1 行第 1 列
- javascript - 用于 Ping 以进行离线检测的 URL
- c++ - C++ 替代预处理器#ifdef / #endif
- python - 将图像淡化为白色
- google-cloud-platform - 计算实例的 GCP gcloud API 过滤标签
- r - 想要根据列名改变平均列的列,但还要从计算中排除某些列?
- python - 查找磁盘何时未连接?