【问题标题】:How to perform an action after NavigationLink is tapped?点击 NavigationLink 后如何执行操作?
【发布时间】:2019-11-17 04:18:40
【问题描述】:

我的第一个视图中有一个加号按钮。看起来像一个 FAB 按钮。在点击 NavigationLink 中包含的某个步骤后,我想隐藏它。到目前为止,我有这样的事情:

ForEach(0 ..< 12) {item in
    NavigationLink(destination: TransactionsDetailsView()) {
        VStack {
            HStack(alignment: .top) {
                Text("List item")
            }
            .padding(EdgeInsets(top: 5, leading: 10, bottom: 5, trailing: 10))
            .foregroundColor(.black)
            Divider()
        }
    }
    .simultaneousGesture(TapGesture().onEnded{
        self.showPlusButton = false
    })
        .onAppear(){
            self.showPlusButton = true
    }
}

单击即可正常工作。但是当我长按 NavigationLink 时它不起作用。我应该如何重写我的代码以包括长按?或者也许我应该让它的工作方式与使用同时手势不同?

【问题讨论】:

    标签: swiftui


    【解决方案1】:

    是的,NavigationLink 不允许这样的同时手势(可能是设计的,可能是由于问题,等等)。

    您期望的行为可能会实现如下(当然如果您需要在列表项中添加一些 chevron,则需要手动添加)

    import SwiftUI
    
    struct TestSimultaneousGesture: View {
        @State var showPlusButton = false
        @State var currentTag: Int?
        var body: some View {
    
            NavigationView {
                List {
                    ForEach(0 ..< 12) { item in
                        VStack {
                            HStack(alignment: .top) {
                                Text("List item")
                                NavigationLink(destination: Text("Details"), tag: item, selection: self.$currentTag) {
                                    EmptyView()
                                }
                            }
                            .padding(EdgeInsets(top: 5, leading: 10, bottom: 5, trailing: 10))
                            .foregroundColor(.black)
                            Divider()
                        }
                        .simultaneousGesture(TapGesture().onEnded{
                            print("Got Tap")
                            self.currentTag = item
                            self.showPlusButton = false
                        })
                        .simultaneousGesture(LongPressGesture().onEnded{_ in
                            print("Got Long Press")
                            self.currentTag = item
                            self.showPlusButton = false
                        })
                        .onAppear(){
                            self.showPlusButton = true
                        }
                    }
                }
            }
        }
    }
    
    struct TestSimultaneousGesture_Previews: PreviewProvider {
        static var previews: some View {
            TestSimultaneousGesture()
        }
    }
    

    【讨论】:

    • 谢谢你,@Asperi。添加 .simultaneousGesture(LongPressGesture(...) 确实有助于触发长按。但我仍然想知道这是否是最好的方法。我可以看到你的代码在 List 中。最初我使用 ScrollView 代替,因为 List我在此列表中的一部分代码存在问题。我还尝试使用一些不同的代码(我将在下面对我的问题的回答中很快发布示例)并且根本不需要同时手势,并且自动添加了 V 形
    • 顺便说一句,如果在您的示例中您可以使用 2 个手势,那么“NavigationLink 不允许同时使用此类手势”是什么意思。你的意思是没有办法用一个命令来处理这两种手势?
    • 不,我的意思是直接将手势修饰符添加到 List 中的常规 NavigationLink - 导航完全停止工作。顺便说一句,你没有告诉任何关于使用 ScrollView 的问题 - 在这种情况下,容器很重要,因为 ScrollView 和 List 中的 NavigationLink 行为不同。以防万一。
    • 是的,@Asperi,你是对的。那个时候我不知道它会有所不同。请在下面的答案中查看我的代码。这次我尝试使用列表。但与您的示例略有不同。另外,如果使用 ScrollView,我还有另一个想法。我尝试在与原始帖子中的 onAppear 相同的级别上使用 onDisappear 修饰符,而不是同时使用手势修饰符。它有点工作,但有一点延迟。新屏幕滑入后,PlusButton 消失了。我想在此之前隐藏它。
    • 感谢您的帮助,@Asperi。经过多次尝试,我认为您的回答是我问题的最佳解决方案。
    【解决方案2】:

    我正在使用以下代码。我更喜欢它而不是 NavigationLink 本身,因为它可以让我重复使用现有的 ButtonStyles。

    
    struct NavigationButton<Destination: View, Label: View>: View {
        var action: () -> Void = { }
        var destination: () -> Destination
        var label: () -> Label
    
        @State private var isActive: Bool = false
    
        var body: some View {
            Button(action: {
                self.action()
                self.isActive.toggle()
            }) {
                self.label()
                  .background(
                    ScrollView { // Fixes a bug where the navigation bar may become hidden on the pushed view
                        NavigationLink(destination: LazyDestination { self.destination() },
                                                     isActive: self.$isActive) { EmptyView() }
                    }
                  )
            }
        }
    }
    
    // This view lets us avoid instantiating our Destination before it has been pushed.
    struct LazyDestination<Destination: View>: View {
        var destination: () -> Destination
        var body: some View {
            self.destination()
        }
    }
    
    

    并使用它:

    var body: some View {
      NavigationButton(
        action: { print("tapped!") },
        destination: { Text("Pushed View") },
        label: { Text("Tap me") }
      )
    }
    

    【讨论】:

    • 谢谢。也许是我没有足够的 SwiftUI 经验,但我不知道如何在我的示例中实现您的解决方案。你写到你更喜欢它而不是 NavigationLink,但后来你的代码中仍然有 NavigationLink。
    • 我添加了一个如何使用它的示例。只需将初始代码放在一个新文件中即可。我的意思是,我会在否则单独使用NavigationLink的地方使用它。
    • 什么是 LazyDestination??
    • @Ravindra_Bhati 为 LazyDestination 添加了代码。这并不重要,但可以很方便。您可以查看this article 了解更多信息。
    • 哇!这个解决方案非常优雅,NavigationButton 应该会在 2020 年成为 SwiftUI 的一部分!
    【解决方案3】:

    我尝试了另一种方法来解决我的问题。最初我没有使用“List”,因为我的部分代码有问题。但这会导致另一个问题:点击 NavigationLink 后,PlusButton 不会在下一个屏幕上消失。这就是我想使用simultaneousGesture 的原因——在点击链接后,也会执行一些操作(这里:PlusButton 将被隐藏)。但效果并不好。

    我尝试了另一种解决方案。使用 List(也许我稍后会解决另一个问题。

    这是我的替代代码。根本不需要同时手势。人字形会自动添加到列表中。 PlusButton 隐藏了我想要的。

    import SwiftUI
    
    struct BookingView: View {
    
        @State private var show_modal: Bool = false
    
        var body: some View {
            NavigationView {
                ZStack {
                    List {
                        DateView()
                            .listRowInsets(EdgeInsets())
    
                        ForEach(0 ..< 12) {item in
                            NavigationLink(destination: BookingDetailsView()) {
                                HStack {
                                    Text("Booking list item")
                                    Spacer()
                                }
                                .padding()
                            }
                        }
                    }.navigationBarTitle(Text("Booking"))
    
                    VStack {
                        Spacer()
                        Button(action: {
                            print("Button Pushed")
                            self.show_modal = true
                        }) {
                            Image(systemName: "plus")
                                .font(.largeTitle)
                                .frame(width: 60, height: 60)
                                .foregroundColor(Color.white)
                        }.sheet(isPresented: self.$show_modal) {
                            BookingAddView()
                        }
                        .background(Color.blue)
                        .cornerRadius(30)
                        .padding()
                        .shadow(color: Color.black.opacity(0.3), radius: 3, x: 3, y: 3)
                    }
                }
    
            }
        }
    
    }
    

    【讨论】:

    • 嗯...这看起来不像与相关代码相关的代码
    • 是的。你的答案更好。我的代码是一种完全避免调用其他操作来解决我原来的问题的方法——在我的视图中隐藏 PlusButton。我无法在评论中发布此代码。这就是我将其作为答案发送的原因。对不起。这里还是新的
    【解决方案4】:

    我尝试过的另一种选择。不使用同时手势,而是使用 onDisappear 修饰符。代码很简单,而且很有效。一个缺点是这些动作的发生会稍有延迟。因为首先目标视图滑入,然后执行操作。这就是为什么我仍然更喜欢@Asperi 的答案,他在我的代码中添加了 .simultaneousGesture(LongPressGesture)。

    ForEach(0 ..< 12) {item in
        NavigationLink(destination: TransactionsDetailsView()) {
            VStack {
                HStack(alignment: .top) {
                    Text("List item")
                }
                .padding(EdgeInsets(top: 5, leading: 10, bottom: 5, trailing: 10))
                .foregroundColor(.black)
                Divider()
            }
        }
        .onDisappear(){
            self.showPlusButton = false
        }
        .onAppear(){
            self.showPlusButton = true
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-21
      • 1970-01-01
      • 1970-01-01
      • 2013-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多