【问题标题】:Is it possible for a NavigationLink to perform an action in addition to navigating to another view?除了导航到另一个视图之外,NavigationLink 是否可以执行操作?
【发布时间】:2019-12-31 03:49:30
【问题描述】:

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

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

【问题讨论】:

标签: swiftui


【解决方案1】:

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

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

【讨论】:

  • 绝妙的解决方案!我之前使用过许多其他人提出的“onAppear()”,但它引起了各种各样的问题。但这既简单又干净。非常感谢。
  • 有没有办法当用户点击“返回”按钮返回到上一个视图时,它可以传回一个变量?甚至强制刷新之前的视图?
  • 这似乎不适用于您有一个项目列表并且它们在 NavigationLink 父级中!?有其他人对此有任何运气吗?
  • 是的,如果您在列表中遵循此技术,它将无法正常工作。
【解决方案2】:

使用 NavigationLink(_:destination:tag:selection:) 初始化程序并将模型的属性作为 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))")
            }
        }
    }
}

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

ContentView().environmentObject(NavigationModel())

在 SceneDelegate 和 SwiftUI 预览中。

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

(它在列表中工作)

【讨论】:

    【解决方案3】:

    您可以使用 NavigationLink(destination:isActive:label:)。使用绑定上的设置器来了解何时点击链接。我注意到可以在内容区域之外点击 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")
        }
    }
    

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

    Tapped
    Tapped
    View Presented
    Tapped
    

    【讨论】:

    • 谢谢。此解决方案适用于接受的解决方案不起作用的列表中
    【解决方案4】:

    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
        }
    }
    

    【讨论】:

      【解决方案5】:

      这对我有用:

      @State private var isActive = false
      
      NavigationLink(destination: MyView(), isActive: $isActive) {
          Button {
              // run your code
              
              // then set
              isActive = true
      
          } label: {
              Text("My Link")
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-03
        • 1970-01-01
        • 2013-11-09
        • 2015-06-11
        相关资源
        最近更新 更多