onTapGesture 在 SwiftUI ScrollView 中不起作用

onTapGesture not work in SwiftUI ScrollView

我想在 SwiftUI 中制作一个段标签页,如下所示。

我的代码如下:

struct ContentView: View {
    @State var index = 0
    @State private var offset: CGFloat = 0
    var body: some View {
        VStack(spacing: 0) {
            HStack() {
                Button("tab1") {
                    self.index = 0
                }
                Button("tab2") {
                    self.index = 1
                }
            }
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(alignment: .center, spacing: 0) {
                    VStack() {
                        List {
                            VStack {
                                HStack() {
                                    Text("tab1 line1")
                                    Spacer()
                                }
                                .frame(height: 126)
                                .contentShape(Rectangle())
                                .onTapGesture {
                                    print("click tab1 line1")
                                }
                            }
                            VStack {
                                HStack() {
                                    Text("tab1 line2")
                                    Spacer()
                                }
                                .frame(height: 126)
                                .contentShape(Rectangle())
                                .onTapGesture {
                                    print("click tab1 line2")
                                }
                            }
                        }
                        .frame(width: UIScreen.main.bounds.size.width, height: 300)
                    }
                    .frame(width: UIScreen.main.bounds.size.width, height: 300)
                    .cornerRadius(30)
                    VStack() {
                        List {
                            VStack {
                                HStack() {
                                    Text("tab2 line1")
                                    Spacer()
                                }
                                .frame(width: UIScreen.main.bounds.size.width, height: 126)
                                .contentShape(Rectangle())
                                .onTapGesture {
                                    print("click tab2 line1")
                                }
                            }
                            VStack {
                                HStack() {
                                    Text("tab2 line2")
                                    Spacer()
                                }
                                .frame(width: UIScreen.main.bounds.size.width, height: 126)
                                .contentShape(Rectangle())
                                .onTapGesture {
                                    print("click tab2 line2")
                                }
                            }
                        }
                        .frame(width: UIScreen.main.bounds.size.width, height: 300)
                        .onAppear() {
                            print("load")
                        }
                    }
                    .frame(width: UIScreen.main.bounds.size.width, height: 300)
                    .cornerRadius(30)
                }
            }
            .content
            .offset(x: self.getOffset())
            .animation(.spring())
            .frame(width: UIScreen.main.bounds.size.width, alignment: .leading)
        }
        .frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
        .background(Color.gray)
    }
    
    private func getOffset() -> CGFloat {
        let offset = CGFloat(self.index) * (-UIScreen.main.bounds.size.width)
        return offset
    }
}

一切正常,期待 tab2 中的 onTapGesture。当点击“tab1”行时,onTapGesture 可以很好地打印“click tab1 line1”或“click tab1 line2”。 点击“tab2”按钮后,页面会滚动到tab2页面。单击列表“tab2”的行时,onTapGesture 不起作用。

我试了一天,找到了两种方法:

  1. 滚动到“tab2”页面后,向上或向下滚动tab2列表,onTapGesture将打印“点击tab2 line1”和“点击tab2 line2”。
  2. 去掉代码.cornerRadius(30),在tab2页面点击也有效

我只想保留列表的半径。如何修复这个令人难以置信的错误?

问题出在这里:

.content
.offset(x: self.getOffset())

复制 滚动视图的内容并将其向右偏移。结果,你点击的是重复的内容,这可能会影响点击手势。

而是使用 ScrollViewReader 滚动 ScrollView,并删除您的 getOffset 代码。

struct ContentView: View {
    @State var index = 0
    @State private var offset: CGFloat = 0
    
    var body: some View {
        VStack(spacing: 0) {
            HStack() {
                Button("tab1") {
                    self.index = 0
                }
                Button("tab2") {
                    self.index = 1
                }
            }
            ScrollView(.horizontal, showsIndicators: false) {
                ScrollViewReader { proxy in
                    HStack(alignment: .center, spacing: 0) {
                        VStack() {
                            List {
                                VStack {
                                    HStack() {
                                        Text("tab1 line1")
                                        Spacer()
                                    }
                                    .frame(height: 126)
                                    .contentShape(Rectangle())
                                    .onTapGesture {
                                        print("click tab1 line1")
                                    }
                                }
                                VStack {
                                    HStack() {
                                        Text("tab1 line2")
                                        Spacer()
                                    }
                                    .frame(height: 126)
                                    .contentShape(Rectangle())
                                    .onTapGesture {
                                        print("click tab1 line2")
                                    }
                                }
                            }
                            .frame(width: UIScreen.main.bounds.size.width, height: 300)
                        }
                        .frame(width: UIScreen.main.bounds.size.width, height: 300)
                        .cornerRadius(30)
                        .id(0) /// set id here
                        
                        VStack() {
                            List {
                                VStack {
                                    HStack() {
                                        Text("tab2 line1")
                                        Spacer()
                                    }
                                    .frame(width: UIScreen.main.bounds.size.width, height: 126)
                                    .contentShape(Rectangle())
                                    .onTapGesture {
                                        print("click tab2 line1")
                                    }
                                }
                                VStack {
                                    HStack() {
                                        Text("tab2 line2")
                                        Spacer()
                                    }
                                    .frame(width: UIScreen.main.bounds.size.width, height: 126)
                                    .contentShape(Rectangle())
                                    .onTapGesture {
                                        print("click tab2 line2")
                                    }
                                }
                            }
                            .frame(width: UIScreen.main.bounds.size.width, height: 300)
                            .onAppear() {
                                print("load")
                            }
                        }
                        .frame(width: UIScreen.main.bounds.size.width, height: 300)
                        .cornerRadius(30)
                        .id(1) /// also set id here
                    }
                    .onChange(of: index) { _ in /// scroll the ScrollView
                        withAnimation(.spring()) {
                            proxy.scrollTo(index)
                        }
                    }
                }
            }
            .frame(width: UIScreen.main.bounds.size.width, alignment: .leading)
        }
        .frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
        .background(Color.gray)
    }
    
}