richy
richy

Reputation: 2825

Why is `onAppear` called for all elements in a `LazyVStack` or `LazyHStack` if it's not inside a `ScrollView`?

I want to create a LazyHStack without a ScrollView so that I can use my own gestures etc.

What does having a ScrollView do to a LazyVStack so that only the visible elements have onAppear called on them?

struct LazyTestView: View {
  @State var nonScrollViewAppears = 0
  @State var scrollViewAppears = 0
  var body: some View {
    VStack {
      Text("Non-ScrollView - Views appeared: \(nonScrollViewAppears)")
      ZStack {
        LazyHStack(spacing:0) {
          ForEach(0..<100, id: \.self) { index in
            Rectangle().fill(.orange).frame(width: 100, height: 100)
              .border(.black)
              .overlay(Text("\(index)"))
              .onAppear {
                nonScrollViewAppears += 1
              }
              .onTapGesture {
                print("tapped: \(index)")
              }
          }
        }
        .frame(width: 100, alignment: .leading)
        .border(.red)
      }
      .frame(width: 150, height: 150)
      .contentShape(Rectangle()) // Blocks hit testing
      .clipped() // Clips the view
      .border(.blue)

      Divider()

      Text("ScrollView - Views appeared: \(scrollViewAppears)")
      ScrollView(.horizontal) {
        LazyHStack(spacing:0) {
          ForEach(0..<100, id: \.self) { index in
            Rectangle().fill(.orange).frame(width: 100, height: 100)
              .border(.black)
              .overlay(Text("\(index)"))
              .onAppear {
                scrollViewAppears += 1
              }
          }
        }
        .frame(width: 100*100, height: 150, alignment: .leading)
        .border(.red)
      } // ScrollView
      .frame(width: 150, height: 150)
      .border(.blue)
    }
  }
}

Screenshot of the view rended by the sample code on iPhone

I've added contentShape(Rectangle()) which blocks the hit testing and clipped() which blocks the rendering of the elements outside the ZStack. I've also tested this on a device.

I'm not sure why it's working like this.

Upvotes: 0

Views: 69

Answers (0)

Related Questions