【问题标题】:View presented twice in SwiftUI on iOS 14在 iOS 14 上的 SwiftUI 中显示两次视图
【发布时间】:2021-01-11 16:09:48
【问题描述】:

我需要基于模型动态呈现视图,因此需要在 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
        }
    }
}

【问题讨论】:

    标签: ios swift view navigation swiftui


    【解决方案1】:

    您需要延迟构建导航链接目标视图(否则它会在第一次刷新时立即创建并且您会看到效果)。

    使用 Xcode 12 / iOS 14 测试

    NavigationLink(destination: DeferView { self.coordinator.nextScreen() }, // << here !!
      isActive: self.$pushNext) {
        EmptyView()
    }
    

    DeferView 取自 other my solution

    【讨论】:

    • 解决了,谢谢。知道 iOS 14 中发生了什么变化以使其成为必要吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 2020-01-16
    • 2021-01-05
    相关资源
    最近更新 更多