SwiftUI Picker blocking input when clipped

Viewed 242

The code example below shows 2 rows as HStacks. The second row contains a Picker which is clipped to 40 x 80

For some reason, it's still creating an invisible view which is blocking user interaction with the button in row 1.

The Toggle switch is drawn above the invisible view, so that works. But the button is drawn beneath it and doesn't work.

If you swap the order of Toggle and Button so Button is on the left, the Button functions normally.

Video example here - https://www.loom.com/share/83542e34b9a546439ad4d99128ff51b6

Very grateful to anyone who can help me figure this out.

import SwiftUI

struct ContentView: View {
    
    @State private var repSelection = 1
    @State private var toggleOn = false
    var body: some View {
        VStack {
            VStack {
                
                //Row 1
                //If the Button is on the right, it's covered by the invisible Picker view and doesn't work. If the button is on the left, it works.
                //The Toggle seems to be drawn above the invisible view and works in either position
                HStack {
                    
                    Toggle("Switch", isOn: $toggleOn)

                    Button("Done"){ print("Tapped Done Button") }.padding().background(Color.gray)

                }
                
                //Row 2
                HStack {
                    
                    Spacer()
                
                    //For some reason, even though the Picker is clipped, it produces an invisible view that covers the button in Row 1,
                    Picker("Reps", selection:$repSelection){
                        ForEach(1...20, id:\.self) {
                            Text("\($0)")
                        }
                    }
                    .frame(maxWidth: 40, maxHeight: 80)
                    .compositingGroup()
                    .clipped()
                    .background(Color.green)
                
                }.background(Color.purple)
            }
            
        }
    }
    
}

struct PlaylistItemAdder_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
1 Answers

This is pretty strange behavior. I guess even though you clip the picker, the background is technically still drawn but not visible. Anyway, it seems to work if you disable Hit Testing on the background layer of the Picker:

          Picker("", selection:$repSelection){
                ForEach(1...20, id:\.self) {
                    Text("\($0)")
                }
            }
            .allowsHitTesting(true) // <-- allow clicking on picker
            .frame(width: 40, height: 80)
            .clipped()
            .background(Color.green)
            .allowsHitTesting(false) // <-- remove clicking on background
Related