mars
mars

Reputation: 427

onTapGesture not work in SwiftUI ScrollView

I want to make a segment tab page in SwiftUI such as bellow.

enter image description here

My code is as bellow:

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

Everything works well expect the onTapGesture in tab2. When tap the line of "tab1",the onTapGesture works well to print "click tab1 line1" or "click tab1 line2". After click button "tab2", the page will scroll to tab2 page. When click the line of list "tab2", onTapGesture not works.

I try a day, and found two methods to make it works:

  1. After scroll to page "tab2", Scroll up or down the tab2 list, the onTapGesture will works to print "click tab2 line1" and "click tab2 line2".
  2. remove the code .cornerRadius(30), the click in tab2 page will also works.

I just want to keep the radius of list. How to fix this incredible bug?

Upvotes: 1

Views: 1498

Answers (1)

aheze
aheze

Reputation: 30308

The problem is here:

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

This duplicates the scrollview's content and offsets it to the right. As a result, what you are tapping is the duplicated content, which probably affects the tap gesture.

Instead, use ScrollViewReader to scroll the ScrollView, and remove your getOffset code.

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

Upvotes: 1

Related Questions