Search code examples
swiftswiftuiscrollviewswiftui-ontapgesture

onTapGesure not registering for background of ScrollView


For some reason, the .onTapGesture event won't fire for the background of the ScrollView, but it does fire correctly when applied to the background of a nested VStack view:

    var body: some View {
        ScrollView {
            VStack {...}
            .background(
                Rectangle()
                    .fill(.red)
                    .onTapGesture {
                        print("!!!CLICKED!!!")
                    }
            )
        }
        .background(
            Rectangle()
                .fill(.green)
                .onTapGesture {
                    print("!!!CLICKED!!!")
                }
        )
    }

So when I click the red area, I'm able to see "!!!CLICKED!!!" printed, but when I click the green area, nothing is printed:

ViewLayout image


Solution

  • To trigger the action on the background of the ScrollView, just move the .onTapGesture() modifier to the bottom of the ScrollView itself, instead of the .background().

    Here below, you will see a sample code that works (I added a couple of variables to notice the effect directly on the screen):

    @State private var clicked = "Nothing"  // For testing purposes only
    @State private var alternate = true     // For testing purposes only
        
    var body: some View {
        ScrollView {
            VStack {
                Text("One")
                Text("Two")
                Text("Three")
                
                Text(clicked)  // For testing purposes: see what was clicked on the screen
                    .padding()
                Text(alternate ? "Clicked" : "... and again")  // See the effect after each click
            }
            .background(
                Rectangle()
                    .fill(.red)
                    .onTapGesture {
                        clicked = "Clicked red"
                        alternate.toggle()
                        print("!!!CLICKED RED!!!")
                    }
            )
        }
        
        // Here is where the modifier should be to trigger the action on the background of the ScrollView
        .onTapGesture {
            clicked = "Clicked green"
            alternate.toggle()
            print("!!!CLICKED GREEN!!!")
        }
        .background(
            Rectangle()
                .fill(.green)
        )
    }