PresentationLink 始终使用相同的目标对象
PresentationLink always use the same destination object
令我惊讶的是,每当我点击嵌入在 PresentationLink 中的按钮时,相同的视图引用始终会出现。我的意思是我们不创建视图的另一个实例。
这是有道理的,因为目标对象是在主体 属性 中创建的,因此除非发生更改,否则不会重新创建。
你们知道我们是否有一种简单的方法可以在每次按下按钮时重新创建一个新视图吗?还是设计使然,应该这样使用?
谢谢!
编辑
经过@dfd 的评论,这似乎是设计的。
现在如何处理这个用例:
Let's say I present a NavigationView and I pushed one view. If I
dismiss and re present, I will go back on the view I previously
pushed. In this case, I believe it's wrong as I'd like the user to go
through the complete flow every single time. How can I make sure that
I go back on the first screen everytime?
谢谢你(再次)!
编辑 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
。
从那里,假设用户向下滑动并因此关闭了演示文稿。当它点击 PresenterExample
中的 PresentationLink
时,它会在 StackSecondView
上重新打开,这不是我想要的。我想再次显示StackFirstView
。
更有意义? :)
第一次尝试:失败
我尝试使用 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())
这 应该 执行以下操作:
应该用presentationCount
来识别StackFirstView
。 SwiftUI 应该将每个具有不同标识符的 StackFirstView
视为一个完全不同的视图。我已经成功地将其用于动画过渡。
它应该在 StackFirstView
被关闭时递增 presentationCount
,以便下一个 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
的状态。请注意,id
必须应用于 Group
的内容,而不是 Group
本身,以解决 SwiftUI 错误。
第三次尝试:成功
我修改了第二次尝试,这样当 presentationCount
是奇数时,它将 StackFirstView
包装在 ZStack
中,而不是使用 id
修饰符。
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())
这行得通。我想 SwiftUI 看到模态的内容每次都是不同的类型(StackFirstView
vs. ZStack<StackFirstView>
),这足以说服它这些是不相关的视图,所以它丢弃了先前呈现的视图重复使用它。
令我惊讶的是,每当我点击嵌入在 PresentationLink 中的按钮时,相同的视图引用始终会出现。我的意思是我们不创建视图的另一个实例。 这是有道理的,因为目标对象是在主体 属性 中创建的,因此除非发生更改,否则不会重新创建。
你们知道我们是否有一种简单的方法可以在每次按下按钮时重新创建一个新视图吗?还是设计使然,应该这样使用?
谢谢!
编辑
经过@dfd 的评论,这似乎是设计的。 现在如何处理这个用例:
Let's say I present a NavigationView and I pushed one view. If I dismiss and re present, I will go back on the view I previously pushed. In this case, I believe it's wrong as I'd like the user to go through the complete flow every single time. How can I make sure that I go back on the first screen everytime?
谢谢你(再次)!
编辑 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
。
从那里,假设用户向下滑动并因此关闭了演示文稿。当它点击 PresenterExample
中的 PresentationLink
时,它会在 StackSecondView
上重新打开,这不是我想要的。我想再次显示StackFirstView
。
更有意义? :)
第一次尝试:失败
我尝试使用 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())
这 应该 执行以下操作:
应该用
presentationCount
来识别StackFirstView
。 SwiftUI 应该将每个具有不同标识符的StackFirstView
视为一个完全不同的视图。我已经成功地将其用于动画过渡。它应该在
StackFirstView
被关闭时递增presentationCount
,以便下一个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
的状态。请注意,id
必须应用于 Group
的内容,而不是 Group
本身,以解决 SwiftUI 错误。
第三次尝试:成功
我修改了第二次尝试,这样当 presentationCount
是奇数时,它将 StackFirstView
包装在 ZStack
中,而不是使用 id
修饰符。
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())
这行得通。我想 SwiftUI 看到模态的内容每次都是不同的类型(StackFirstView
vs. ZStack<StackFirstView>
),这足以说服它这些是不相关的视图,所以它丢弃了先前呈现的视图重复使用它。