PresentationLink始终使用相同的目标对象

时间:2019-07-15 20:17:02

标签: ios swift swiftui

令我感到惊讶的是,每当我点击PresentationLink中嵌入的按钮时,始终会出现相同的视图引用。我的意思是我们不创建视图的另一个实例。 这是有道理的,因为目标对象是在body属性内创建的,因此除非发生更改,否则不会重新创建。

你们知道我们每次点击按钮时是否都有一种简单的方法来重新创建新视图?还是设计使然,应该像这样使用?

谢谢!

编辑

@dfd发表评论后,这似乎是设计使然。 现在如何处理该用例:

  

假设我展示了一个NavigationView,然后按下了一个视图。如果我   撤消并发表讲话,我将回到以前的观点   推。在这种情况下,我认为这是错误的,因为我希望用户离开   每遍一次完整的流程。我如何确保   我每次都回到第一个屏幕吗?

再次感谢您!

编辑2

以下是一些代码:

struct PresenterExample : View {
    var body: some View {
        VStack {
            PresentationLink(destination: CandidateCreateProfileJobView()) {
                Text("Present")
            }
        }
    }
}

struct StackFirstView : View {
    var body: some View {
        NavigationLink(destination: StackSecondView()) {
            Text("Got to view 2")
        }
    }
}

struct StackSecondView : View {
    var body: some View {
        Text("View 2")
    }
}

在这种情况下,将PresenterExample出现StackFirstView,它将从NavigationLink中推送StackSecondView。 假设用户从那里向下滑动,因此关闭了演示文稿。在PresentationLink中的PresenterExample上单击时,它将在StackSecondView上重新打开,这不是我想要的。我想再次显示StackFirstView

更有意义吗? :)

1 个答案:

答案 0 :(得分:1)

首次尝试:失败

我尝试使用id修饰符告诉SwiftUI将StackFirstView的每次显示都视为与以前的视图无关的全新视图:

import SwiftUI

struct PresenterExample : View {
    var body: some View {
        VStack {
            PresentationLink("Present", destination:
                StackFirstView()
                    .onDisappear {
                        print("onDisappear")
                        self.presentationCount += 1
                }
            )
        }
    }

    @State private var presentationCount = 0
}

struct StackFirstView : View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: StackSecondView()) {
                Text("Go to view 2")
            }.navigationBarTitle("StackFirstView")
        }
    }
}

struct StackSecondView : View {
    var body: some View {
        Text("View 2")
            .navigationBarTitle("StackSecondView")
    }
}

import PlaygroundSupport

PlaygroundPage.current.liveView = UIHostingController(rootView: PresenterExample())

执行以下操作:

  • 它应通过StackFirstView来标识presentationCount。 SwiftUI应该将具有不同标识符的每个StackFirstView视为完全不同的视图。我已经成功地将其用于动画过渡。

  • 当取消presentationCount时,它应递增StackFirstView,以便下一个StackFirstView获得不同的标识符。

问题在于,SwiftUI永远不会为呈现的视图或其任何子视图调用onDisappear闭包。我很确定这是一个SwiftUI错误(从Xcode 11 beta 3开始)。我提交了FB6687752。

第二次尝试:失败成功

接下来,我尝试使用presentation(Modal?)修饰符自己管理演示文稿,因此不需要onDisappear修饰符:

import SwiftUI

struct PresenterExample : View {
    var body: some View {
        VStack {
            Button("Present") {
                self.presentModal()
            }.presentation(modal)
        }
    }

    @State private var shouldPresent = false
    @State private var presentationCount = 0

    private func presentModal() {
        presentationCount += 1
        shouldPresent = true
    }

    private var modal: Modal? {
        guard shouldPresent else { return nil }
        return Modal(StackFirstView().id(presentationCount), onDismiss: { self.shouldPresent = false })
    }
}

struct StackFirstView : View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: StackSecondView()) {
                Text("Go to view 2")
            }.navigationBarTitle("StackFirstView")
        }
    }
}

struct StackSecondView : View {
    var body: some View {
        Text("View 2")
    }
}

import PlaygroundSupport

PlaygroundPage.current.liveView = UIHostingController(rootView: PresenterExample())

这以另一种方式失败。 StackFirstView的第二次和以后的演示仅显示空白视图。再次,我很确定这是一个SwiftUI错误。我提交了FB6687804。

我尝试将presentationCount向下传递到StackFirstView,然后将.id(presentationCount)修饰符应用于NavigationView的内容。如果在显示StackSecondView时取消模态并再次显示模态,则会使运动场崩溃。我提交了FB6687850。

更新

This tweet from Ryan Ashcraft向我展示了一种解决方法,可以使第二次尝试有效。它将Modal的内容包装在Group中,并将id修饰符应用于Group的内容:

import SwiftUI

struct PresenterExample : View {
    var body: some View {
        VStack {
            Button("Present") {
                self.presentModal()
            }.presentation(modal)
        }
    }

    @State private var shouldPresent = false
    @State private var presentationCount = 0

    private func presentModal() {
        presentationCount += 1
        shouldPresent = true
    }

    private var modal: Modal? {
        guard shouldPresent else { return nil }
        return Modal(Group { StackFirstView().id(presentationCount) }, onDismiss: { self.shouldPresent = false })
    }
}

struct StackFirstView : View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: StackSecondView()) {
                Text("Go to view 2")
            }.navigationBarTitle("StackFirstView")
        }
    }
}

struct StackSecondView : View {
    var body: some View {
        Text("View 2")
    }
}

import PlaygroundSupport

PlaygroundPage.current.liveView = UIHostingController(rootView: PresenterExample())

此修订后的第二次尝试成功重置了每个演示文稿上Modal的状态。请注意,{@ {1}}必须应用于id的内容,而不是Group本身,才能解决SwiftUI错误。

第三次尝试:成功

我修改了第二种尝试,以便当Group为奇数时,它不使用id修饰符,而是将StackFirstView包装在ZStack内。

presentationCount

这有效。我想SwiftUI会看到模态的内容每次都是不同的类型(import SwiftUI struct PresenterExample : View { var body: some View { VStack { Button("Present") { self.presentModal() }.presentation(modal) } } @State private var shouldPresent = false @State private var presentationCount = 0 private func presentModal() { presentationCount += 1 shouldPresent = true } private var modal: Modal? { guard shouldPresent else { return nil } if presentationCount.isMultiple(of: 2) { return Modal(presentationContent, onDismiss: { self.shouldPresent = false }) } else { return Modal(ZStack { presentationContent }, onDismiss: { self.shouldPresent = false }) } } private var presentationContent: some View { StackFirstView() } } struct StackFirstView : View { var body: some View { NavigationView { NavigationLink(destination: StackSecondView()) { Text("Go to view 2") }.navigationBarTitle("StackFirstView") } } } struct StackSecondView : View { var body: some View { Text("View 2") } } import PlaygroundSupport PlaygroundPage.current.liveView = UIHostingController(rootView: PresenterExample()) StackFirstView),足以说服它们是不相关的视图,因此它代替了先前提供的视图重用它。