现在我有一个导航链接
NavigationView {
NavigationLink(destination: AnotherView())) {
Text("Click Here")
}
}
.navigationBarTitle("SwiftUI")
我想发生的事情是,当我单击导航链接时,我希望实例化一个对象并将其放入数据库中。
换句话说,我的问题是:除了使用NavigationLink时仅推送新视图之外,您还如何执行工作?
答案 0 :(得分:2)
对于您描述的情况,这是最简单的方法
NavigationView {
NavigationLink("Click Here", destination:
AnotherView()
.onAppear {
// any action having access to current view context
})
}
答案 1 :(得分:1)
SwiftUI并没有提供简便的方法,但是确实提供了一种方法。您应该使用Button
,其动作会触发NavigationLink
。
问题在于,执行此操作的代码既繁琐又丑陋。因此,我编写了一个控件,将其包装起来类似于Button
和NavigationLink
的爱子。
struct ActionNavigationLink<Destination: View, Content: View>: View {
private let destination: Destination
private let content: Content
private let action: (NavigationToken) -> ()
@State private var continueToDestination: Bool = false
init(
destination: Destination,
action: @escaping (NavigationToken) -> (),
@ViewBuilder content: () -> Content
) {
self.destination = destination
self.action = action
self.content = content()
}
var body: some View {
Button(action: buttonAction, label: { content })
.background(
NavigationLink(
destination: destination,
isActive: $continueToDestination,
label: { EmptyView() }
)
)
}
private func buttonAction() {
let token = NavigationToken {
self.continueToDestination = true
}
action(token)
}
}
NavigationToken
是一个非常简单的结构,可以执行操作。该动作定义了一旦触发导航将如何执行。
struct NavigationToken {
private let navigationAction: () -> ()
fileprivate init(_ action: @escaping () -> ()) {
self.navigationAction = action
}
func navigate() {
navigationAction()
}
}
此令牌将传递给您使用此控件提供的操作,以便在实际执行导航时完全控制您。因此,如果您需要执行一些API调用并且仅在回调返回后进行导航,那么您完全可以做到这一点。
在这里,我通过将导航延迟3秒来模拟API调用。
ActionNavigationLink(
destination: EmptyView(),
action: { token in
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
token.navigate()
}
}
) {
Text("Delayed Navigation")
}
完整来源可在this gist上找到。
答案 2 :(得分:0)
NavigationLink
有一些接受Binding
的重载。您通过绑定初始化它,并在setter中产生副作用,或者类似地,您可以使用具有某些@Published
属性的模型,并订阅其内部发布者。这是一个同时执行这两个操作的示例:
class Model: ObservableObject {
@Published var isLinkActive = false
var subscriptions = Set<AnyCancellable>()
init() {
$isLinkActive
.sink { _ in
print("I'm a side effect in the model")
}
.store(in: &subscriptions)
}
}
struct ContentView: View {
@ObservedObject var model: Model
let isLinkActive: Binding<Bool>
init(model: Model = .init()) {
self.model = model
self.isLinkActive = Binding<Bool>(
get: { [model] in model.isLinkActive},
set: { [model] in
print("I'm a side effect in the binding!")
model.isLinkActive = $0
})
}
var body: some View {
NavigationView {
NavigationLink("hello", destination: Color.red, isActive: isLinkActive)
}
}
}