除了导航到另一个视图之外,NavigationLink 是否可以执行操作?

Jng*_*n22 22 swiftui

我正在尝试创建一个按钮,它不仅可以导航到另一个视图,还可以同时运行一个函数。我尝试将 NavigationLink 和 Button 嵌入到 Stack 中,但我只能单击 Button。

ZStack {
    NavigationLink(destination: TradeView(trade: trade)) {
        TradeButton()
    }
    Button(action: {
        print("Hello world!") //this is the only thing that runs
    }) {
        TradeButton()
    }
}
Run Code Online (Sandbox Code Playgroud)

Ngu*_*Hào 39

您可以使用 .simultaneousGesture 来做到这一点。NavigationLink 将导航并同时执行您想要的操作:

NavigationLink(destination: TradeView(trade: trade)) {
                        Text("Trade View Link")
                    }.simultaneousGesture(TapGesture().onEnded{
                    print("Hello world!")
                })
Run Code Online (Sandbox Code Playgroud)

  • 这似乎不适用于您有一个项目列表并且它们位于 NavigationLink 父级中!?还有其他人有这样的运气吗? (9认同)
  • 是的,如果您在列表中遵循此技术,它将不起作用。 (7认同)
  • 很棒的解决方案!我之前使用过许多其他人提出的“onAppear()”,但它引起了各种各样的问题。但这既简单又干净。非常感谢。 (2认同)

hst*_*tdt 11

NavigationLink+ isActive+onChange(of:)

// part 1
@State private var isPushed = false

// part 2
NavigationLink(destination: EmptyView(), isActive: $isPushed, label: {
    Text("")
})

// part 3
.onChange(of: isPushed) { (newValue) in
    if newValue {
        // do what you want
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是最干净的方法,尽管从 iOS 16 开始已弃用 (2认同)

toa*_*oad 9

这对我来说有效:

@State private var isActive = false

NavigationLink(destination: MyView(), isActive: $isActive) {
    Button {
        // run your code
        
        // then set
        isActive = true

    } label: {
        Text("My Link")
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

使用 NavigationLink(_:destination:tag:selection:) 初始值设定项并将模型的属性作为选择参数传递。因为它是双向绑定,所以您可以为此属性定义didset观察器,并在那里调用您的函数。

struct ContentView: View {
    @EnvironmentObject var navigationModel: NavigationModel

    var body: some View {
        NavigationView {
            List(0 ..< 10, id: \.self) { row in
                NavigationLink(destination: DetailView(id: row),
                               tag: row,
                               selection: self.$navigationModel.linkSelection) {
                    Text("Link \(row)")
                }
            }
        }
    }
}

struct DetailView: View {
    var id: Int;

    var body: some View {
       Text("DetailView\(id)")
    }
}

class NavigationModel: ObservableObject {
    @Published var linkSelection: Int? = nil {
        didSet {
            if let linkSelection = linkSelection {
                // action
                print("selected: \(String(describing: linkSelection))")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在这个示例中,您需要将模型作为环境对象传递给 ContentView:

ContentView().environmentObject(NavigationModel())
Run Code Online (Sandbox Code Playgroud)

在 SceneDelegate 和 SwiftUI 预览中。

该模型符合 ObservableObject 协议,并且该属性必须具有 @Published 属性。

(它在列表中工作)


小智 5

您可以使用 NavigationLink(destination:isActive:label:)。使用绑定上的 setter 来了解何时点击链接。我注意到可以在内容区域之外点击 NavigationLink,这种方法也可以捕获这些点击。

struct Sidebar: View {
    @State var isTapped = false

    var body: some View {
        NavigationLink(destination: ViewToPresent(),
                       isActive: Binding<Bool>(get: { isTapped },
                                               set: { isTapped = $0; print("Tapped") }),
                       label: { Text("Link") })
    }
}

struct ViewToPresent: View {
    var body: some View {
        print("View Presented")
        return Text("View Presented")
    }
}
Run Code Online (Sandbox Code Playgroud)

我唯一注意到的是 setter 触发了三次,其中一次是在它出现之后。这是输出:

Tapped
Tapped
View Presented
Tapped
Run Code Online (Sandbox Code Playgroud)

  • 谢谢。此解决方案适用于列表,其中接受的解决方案不起作用 (2认同)