0

The following code will render a list of items and a button to shuffle them and change their height withAnimation.

If you scroll down and shuffle it you will eventually see glitches in the animation, mostly consisting of ghost items animating on top of other items and disappearing.

Does anyone know why this is happening, and how to stop it happening? The issue goes away entirely if I use a VStack, but using a VStack brings its own problems.

import SwiftUI

struct Item: Identifiable {
  let id = UUID()
  var height: CGFloat
  var label: String
}

struct ContentView: View {
  @State private var items: [Item] =
    (0..<30).map { i in Item(height: .random(in: 80...220), label: "Row \(i)") }

  var body: some View {
    NavigationStack {
      ScrollView {
        LazyVStack(spacing: 8) {
          ForEach(items) { item in
            Text(item.label)
              .frame(maxWidth: .infinity)
              .frame(height: item.height)
              .background(.gray.opacity(0.15))
              .clipShape(RoundedRectangle(cornerRadius: 12))
              .padding(.horizontal)
          }
        }
        .padding(.vertical)
      }
      .navigationTitle("LazyVStack Demo")
      .toolbar {
        ToolbarItem(placement: .topBarTrailing) {
          Button("Shuffle") {
            withAnimation() {
              items.shuffle()
              for i in items.indices {
                items[i].height = .random(in: 80...220)
              }
            }
          }
        }
      }
    }
  }
}

#Preview { ContentView() }

3
  • You could try using Button("Shuffle") { items.shuffle() for i in items.indices { withAnimation { items[i].height = .random(in: 80...220) } } }, to alleviate the burden on withAnimation Commented Sep 18 at 2:22
  • Try applying .geometryGroup() to the LazyVStack Commented Sep 18 at 5:55
  • This question is similar to: SwiftUI content jumping issue with LazyHStack embedded in a horizontal ScrollView in iOS 18. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Sep 18 at 5:56

1 Answer 1

0

I briefly noticed that the visual glitches were appearing alongside scroll position updates. This led me to consider the possibility of this being a ScrollView + LazyVStack automatic scroll preservation issue. Lo and behold, this fixes the problem:

var tx = Transaction()
tx.scrollContentOffsetAdjustmentBehavior = .disabled
tx.animation = .default
withTransaction(tx) {
  items.shuffle()
  for i in items.indices {
    items[i].height = .random(in: 80...220)
  }
}
Sign up to request clarification or add additional context in comments.

6 Comments

When I put the new logic next to old logic, I don't see a whole lot of a difference, if any. This may be a build-location issue. Also, I don't feel like I have a clear vision of what your desired result looks like.
I've added a video example of the buggy behavior I was talking about in the post. In case it's useful, I tested this on iOS 26/iPhone 15 pro.
Video? Well if your satisfied, Im satisfied. Best regards. @styke
Sorry I'm trying to get the GIF under 10mb. Didn't think you'd notice so quickly lol. Bear with me.
So you are satisfied with your results? I would bother posting the gif unless you still think there's room for improvement? @styke
Have a good day. @styke

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.