繁体   English   中英

如何使带有 TapGesture 和 LongPressGesture 的 NavigationLink 在 SwiftUI 中同时工作?

[英]How can I make a NavigationLink with TapGesture and LongPressGesture working simultaneously together in SwiftUI?

是否可以让 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不会工作?

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

这是可能方法的简化演示。 使用 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 !!
            }
    }
}

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

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

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
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM