1

I have a view which contains a button. The view with the button is created from a forEach loop. For some reason only some buttons are tappable and others are not.

The parent view contains a NavigationView, a scroll view inside the NavigationView, a lazyVStack inside of the scroll view, a forEachloop in that lazyVStack and in that for loop is the child view that contains the button.

struct ContentView: View {

  let peoples:[Person] = Bundle.main.decode("data.json")

  var body: some View {
    let columns = [
      GridItem(.flexible(minimum: 300), spacing: 10)
    ]

    NavigationView {
      ScrollView(.vertical) {
        LazyVStack {
          ForEach(peoples, id: \.self) { person in
            PersonView(name: person.Name, age: person.Age)
          }
        }
        .navigationTitle("A list of people")
        .navigationViewStyle(DefaultNavigationViewStyle())
        .padding()
      }
    }
  }
}

The child view is bellow. I suspect the scroll view is stealing the user input, but I am not sure why or how to overcome it. Some buttons are tapeable and some are not.

struct PersonView: View {

  @Environment(\.colorScheme) var colorScheme

  var name: String
  var age: Int

  var body: some View {
    VStack(alignment:.leading) {
      Image("randoPerson")
        .resizable()
        .scaledToFill()
        .frame(minWidth: nil, idealWidth: nil,
               maxWidth: UIScreen.main.bounds.width, minHeight: nil,
               idealHeight: nil, maxHeight: 300, alignment: .center)
        .clipped()
      VStack(alignment: .leading, spacing: 6) {
        Text("name")
          .fontWeight(.heavy)
          .padding(.leading)

        Text("Age \(age)")
          .foregroundColor(Color.gray)
          .padding([.leading,.bottom])


        Button(action: { print("I was tapped") }) {
          HStack {
            Image(systemName: "message.fill")
              .font(.title)
              .foregroundColor(.white)
              .padding(.leading)

            Text("Message them")
              .font(.subheadline)
              .foregroundColor(.white)
              .padding()
          }
          .background(Color.blue)
        }
        .padding()
      }
      .background(Color(UIColor.systemBackground).cornerRadius(15))
      .shadow(color:colorScheme == .dark
                ? Color.white.opacity(0.2)
                : Color.black.opacity(0.2),
              radius: 7, x: 0, y: 2)
    }
  }
}
Roland Lariotte
  • 2,606
  • 1
  • 16
  • 40
Taylor Simpson
  • 940
  • 1
  • 10
  • 27

1 Answers1

0

To fix the issue, you can add an id: UUID associated to a Person and iterate between the Person, inside the ForEach using their ID.

You will also noticed that I added the value as lowercases to respect the Swift convention.

struct Person {

  let id: UUID // Add this value
  var name: String
  var age: Int
}

So here is the ContentView with the id replacing \.self:

struct ContentView: View {

  let peoples: [Person] = Bundle.main.decode("data.json")

  var body: some View {
    NavigationView {
      ScrollView(.vertical) {
        LazyVStack {
          ForEach(peoples, id: \.id) { person in  // id replace \.self here
            PersonView(name: person.name, age: person.age)  // removed uppercase
          }
        }
        .navigationTitle("A list of people")
        .navigationViewStyle(DefaultNavigationViewStyle())
        .padding()
      }
    }
  }
}
Roland Lariotte
  • 2,606
  • 1
  • 16
  • 40