4

我在我的项目中使用 SwfitUI,并且我有一个 NavigationView 和 List。我在打开详细视图并单击导航返回按钮后单击单元格。单击导航返回按钮后,我想删除视图(它是 SwiftUI 中的结构)。因为如果我再次单击相同的单元格或按钮,它不会初始化新视图,而是显示旧视图。我想刷新这个视图。我该怎么办?

我的 FirstView 结构是:

struct FirstView: View {

    @ObservedObject var viewModel: FirstViewModel

    var body: some View {
        List(self.viewModel.objects, id: \.id) { object in
            ZStack {
                DetailViewCell(object: object)
                NavigationLink(destination: DetailViewBuilder.make(object)) {
                    EmptyView()
                }.buttonStyle(PlainButtonStyle())
            }
        }
    }
}

我的 DetailView 结构是:

struct DetailView: View {

    @ObservedObject var viewModel: DetailViewModel

    var body: some View {
        ZStack(alignment: .top) {
            Color.mainBackground.edgesIgnoringSafeArea(.all)
            VStack {
                ZStack {
                    Image("Square")
                    Image(self.viewModel.currentImage)
                }
                Text(self.viewModel.currentText)
                    .padding()
                    .frame(alignment: .center)
                    .minimumScaleFactor(0.1)
                Spacer()
                Button(action: {
                    self.viewModel.pressedPlayOrPauseButton()
                }, label: {
                    Image(self.viewModel.isPlaying ? "Pause" : "Play").foregroundColor(Color("Orange"))
                }).padding()
            }
        }
    }
}

首先,我通过单击 FirstView 中的一个单元格来查看详细信息。然后我用返回按钮回来。我再次单击单元格以转到详细信息,但未打开新视图。它显示了旧视图。

在我忘记之前,我的 Builder 类是:

final class DetailViewBuilder {
    static func make(object: Something) -> DetailView {

        let viewModel = DetailViewModel(object: object)
        let view = DetailView(viewModel: viewModel)

        return view
    }
}

注意:如果我将使用 Sheet Presented,它就可以工作。它正在创建新视图。但我想使用 NavigationLink。谢谢你。

4

2 回答 2

12

你只需要在你的构建器中延迟你的目的地创建,这@ViewBuilder是一个很好的工具。

它可以使用以下包装器仅在何时body呈现时创建真正的目的地(即在您的情况下明确地在导航时单击)

使用 Xcode 11.4 / iOS 13.4 测试

struct DeferView<Content: View>: View {
    let content: () -> Content

    init(@ViewBuilder _ content: @escaping () -> Content) {
        self.content = content
    }
    var body: some View {
        content()          // << everything is created here
    }
}

现在你的建造者

final class DetailViewBuilder {
    static func make(object: Something) -> some View {
        DeferView {
           DetailView(viewModel: DetailViewModel(object: object))
        }
    }
}
于 2020-04-16T04:52:39.393 回答
1

SwiftUI 会NavigationView急切地初始化链接,因此您不能每次都依赖它们的初始化程序来运行。如果您为 DetailView 编写自定义 init()

    init(viewModel: DetailViewModel) {
    self.viewModel = viewModel
    print("Initialising \(self)")
}

当您的 FirstView 加载时,您会看到每个导航链接的行打印出来。

根据您想要做什么,您可以.onAppear {}在 DetailView 上实现一个闭包,这将在视图出现时更改数据。尝试提供实现示例有点棘手,因为我不确定您在这里的具体目标是什么。

对此有一些有趣的讨论: https ://www.notion.so/Lazy-Loading-Data-with-SwiftUI-and-Combine-70546ec6aca3481f80d104cd1f10a31a

这里的任何建议看起来是否与您正在尝试做的事情相关?

于 2020-04-15T21:41:59.703 回答