swiftuiswiftui-viewswiftui-ontapgesture

SwiftUI - How to use onTapGesture for entire row of a VStack


I am creating a search bar view that gets data from an API, the Text highlighted in red (image below) is what I want to pass into my userDefault String upon a tap.

This works as long as I tap the red highlighted text (image below).

Is it possible to get that value when you tap anywhere in that row including the white space?

Here are the State variables,

@State var model: [SearchModel]
var defaults = UserDefaults.standard
@State var isOpen: Bool = false

I won't show all of the code since the issue is only with the code below. As you can see my values are in the ForEach. I just want to have it so that if a user clicks on the white space of the row, the code in the onTapGesture is executed.

ZStack {
        Color(UIColor.white)
            .ignoresSafeArea()
        ScrollView(showsIndicators: false) {
            LazyVStack {
                ForEach(model) { value in
                    VStack(alignment: .leading) {
                        HStack {
                            Text(value.name)
                                .font(.system(size: 15))
                                .background(Color.red)
                                .padding(.trailing, 10.0)
                                .onTapGesture {
                                    isOpen = true
                // I set the value here
                                    defaults.setValue(value.name, forKey: "location") 
                                }.fullScreenCover(isPresented: $isOpen, content: MainView.init)
                    
                        }
                        HStack {
                            Text(value.statelong)
                                .foregroundColor(Color.gray)
                                .font(.system(size: 13))
                            Spacer()
                        }
                        
                    }
                    VStack {
                        Spacer()
                        Divider()
                    }
                    
                }
                
                
            }.padding(.leading, 20.0)
            
            
        }
        
    }
    .listRowInsets(.none)

SwiftUI View with text with a red background


Solution

  • It only works for the highlighted text because the onTapGesture is on the Text view.

    1. Using a HStack()

    I would embed the VStack in a HStack and add a Spacer() to fill the entire area, then place the onTapGesture to the HStack, like this:

        ForEach(model) { value in
                    HStack{
                        VStack(alignment: .leading) {
                            HStack {
                                Text(value.name)
                                    .font(.system(size: 15))
                                    .background(Color.red)
                                    .padding(.trailing, 10.0)
                            }
                            HStack {
                                Text(value.statelong)
                                    .foregroundColor(Color.gray)
                                    .font(.system(size: 13))
                                Spacer()
                            }
                            
                        }
                        Spacer()
                    }.contentShape(Rectangle())
                    .onTapGesture {
                        isOpen = true
                        defaults.setValue(value.name, forKey: "location")
                    }.fullScreenCover(isPresented: $isOpen, content: MainView.init)
                }
    

    2. Using a ZStack()

    Or you could use a ZStack to make a full view background and place the onTapGesture on the ZStack, add .frame(maxWidth: .infinity) to the ZStack to fill the entire available width, like this:

     ForEach(model) { value in
                    ZStack {
                        VStack(alignment: .leading) {
                            HStack {
                                Text(value.name)
                                    .font(.system(size: 15))
                                    .background(Color.red)
                                    .padding(.trailing, 10.0)
                            }
                            HStack {
                                Text(value.statelong)
                                    .foregroundColor(Color.gray)
                                    .font(.system(size: 13))
                                Spacer()
                            }
                            
                        }
                        Spacer()
                    }.contentShape(Rectangle())
                    .frame(maxWidth: .infinity)
                    .onTapGesture {
                        isOpen = true
                        defaults.setValue(value.name, forKey: "location")
                    }.fullScreenCover(isPresented: $isOpen, content: MainView.init)
                }