【问题标题】:How can I make a NavigationLink with TapGesture and LongPressGesture working simultaneously together in SwiftUI?如何在 SwiftUI 中同时使用 TapGesture 和 LongPressGesture 制作 NavigationLink?
【发布时间】:2021-04-14 20:19:10
【问题描述】:

是否可以让 NavigationView 链接与点击手势 (onLongPressGesture) 共存!?

我不能让它为我的生活工作......

ScrollView {   
                
    ForEach(self.itemStore.items) { p in
                    
        NavigationLink(destination: Details(p: p)) {

            CardDetector(p: p, position: self.position)
                    
        }
                    
    }

}

struct CardDetector: View {

    var p: ListData

    @State var position: CardPosition

    @Namespace var namespace

    var body: some View {
    
        Group {

        switch position {
            
            case .small:
                
                smallcardView(p: p, namespace: namespace)
                    .padding()
                    .frame(maxWidth: .infinity)
                    .frame(height: 120)
                    .background(BlurView(style: .regular))
                    .cornerRadius(10)
                    .padding(.vertical,6)
                    .onLongPressGesture {
                    
                        withAnimation {
                        
                            position = .big
                    
                        }
                
                    }
                    .padding(.horizontal)

这会导致滚动问题...他们说解决方案是添加一个onTapGesture(根据答案:Longpress and list scrolling)但随后NavigationLink 将不起作用!?

【问题讨论】:

    标签: ios swiftui


    【解决方案1】:

    解决方案是将链接与手势分开,以编程方式激活链接。在这种情况下,动作、手势和滚动不会发生冲突。

    这里是可能方法的简化演示。使用 Xcode 12.4 / iOS 14.4 测试

    struct ContentView: View {
        var body: some View {
            NavigationView {
                List(0..<10) {
                    LinkCard(number: $0 + 1)
                }
            }
        }
    }
    
    struct LinkCard: View {
        let number: Int
        @State private var isActive = false
        @State private var isBig = false
    
        var body: some View {
            RoundedRectangle(cornerRadius: 12).fill(Color.yellow)
                .frame(height: isBig ? 400 : 100)
                .overlay(Text("Card \(number)"))
                .background(NavigationLink(
                    destination: Text("Details \(number)"),
                    isActive: $isActive) {
                    EmptyView()
                })
                .onTapGesture {
                    isActive.toggle()    // << activate link !!
                }
                .onLongPressGesture {
                    isBig.toggle()       // << alterante action !!
                }
        }
    }
    

    【讨论】:

    • 这也可以通过滚动视图来完成,还是应该专门使用列表?我会尽快尝试您的解决方案...我希望它适用于我的用例!
    • 我收到以下错误Missing argument for the parameter #1 in call - insert '&lt;#LocalizedStringKey#&gt;'.background(NavigationLink( destination: Text("Details \(number)"), isActive: $isActive) { EmptyView() })
    • 所以我只是放了一个唯一的字符串来满足错误,但你的解决方案有效!!!男人你永远不会失望!
    【解决方案2】:

    这是一个需要解释的复杂项目,但我尝试:为了能够直接链接到视图,而不仅仅是简单的StringText,我在@987654323 中定义了符合视图协议的内容类型@结构。因此,您可以链接您已经设计的任何视图。

    为了让点击实际上能够打开链接,我们应该使用自定义绑定。

    struct ContentView: View {
        
        @State private var items: [Item] = [Item(stringValue: "Link 0", destination: Text("Destination 0").foregroundColor(Color.red)),
                                            Item(stringValue: "Link 1", destination: Text("Destination 1").foregroundColor(Color.green)),
                                            Item(stringValue: "Link 2", destination: Text("Destination 2").foregroundColor(Color.blue))]
        
        var body: some View {
            
            NavigationView {
                
                Form {
                    
                    ForEach(items.indices, id: \.self ) { index in
                        
                        NavigationLink(destination: items[index].destination , isActive: Binding.init(get: { () -> Bool in return items[index].isActive },
                                                                                                      set: { (newValue) in items[index].isActive = newValue })) {
                            
                            Color.white.opacity(0.01)
                                .overlay(Text(items[index].stringValue), alignment: .leading)
                                .onTapGesture { items[index].isActive.toggle(); print("TapGesture! on Index:", index.description) }
                                .onLongPressGesture { print("LongPressGesture! on Index:", index.description) }
                            
    
                        }
                        
                    }
                    
                }
                
            }
            
        }
    
    }
    

    struct Item<Content: View>: Identifiable {
        let id: UUID = UUID()
        var stringValue: String
        var isActive: Bool = Bool()
        var destination: Content
    }
    

    【讨论】:

    • @Learn2Code:答案已更新,现在一切正常!
    猜你喜欢
    • 2020-10-25
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    • 2022-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-21
    相关资源
    最近更新 更多