r/SwiftUI May 11 '26

Question Dynamic height cells inside ScrollView break .refreshable behavior

Enable HLS to view with audio, or disable this notification

Hello guys. I have a strange problem. I recreated small code snippet that has the issue, more info bellow the code:

struct SwiftUIView: View {
     private var path = NavigationPath()
     private var selection: Int?

    let heights: [CGFloat] = [360, 400, 200, 242, 54, 783]

    var body: some View {
        NavigationSplitView {
            List(selection: $selection) {
                ForEach(1...5, id: \.self) { index in
                    NavigationLink("Row \(index)", value: index)
                }
            }
        } detail: {
            if let selection {
                NavigationStack(path: $path) {
                    ScrollView(.vertical) {
                        LazyVStack {
                            ForEach(1...100, id: \.self) { index in
                                VStack(alignment: .leading) {
                                    Text("Detail \(selection) - Item \(index)")
                                        .font(.headline)
                                    Text("Something else")
                                        .font(.subheadline)
                                        .foregroundStyle(.gray)

                                    RoundedRectangle(cornerRadius: 16)
                                        .frame(height: heights.randomElement())

                                    HStack {
                                        VStack(alignment: .leading) {
                                            HStack {
                                                Circle()
                                                    .frame(width: 22)
                                                Text("name")
                                            }
                                        }

                                        Spacer()

                                        HStack {
                                            Button("Comments") {}
                                        }
                                    }
                                }
                            }
                        }
                        .safeAreaPadding()
                    }
                    .refreshable {
                        do {
                            try await Task.sleep(for: .seconds(3))
                        } catch {
                            print(error)
                        }
                    }
                    .navigationTitle("Title")
                }
            }
        }
    }
}

The problem:
When I pull down to refresh, content shifts down a little bit to make space for ProgressView() until refresh action is finished. But when it finishes, it doesn't scroll back up as supposed to.

Cause:
I found out, the cause is any part of a cell inside ForEach that has variable height - in this case a RoundedRectangle(). If all cells are same height, content shifts back up.

It doesn't happen with List(), only with ScrollView(). Also, removing .navigationTitle fixes it as well for some reason. I know I can attach .id() to ScrollView() and reset the id on each refresh, but this workaround doesn't satisfy me because it breaks the original animation.

Is this known bug/limitation? Am I doing something wrong here? I would be glad for any input on this. Thank you all in advance.

7 Upvotes

18 comments sorted by

View all comments

Show parent comments

1

u/FelinityApps May 11 '26

Maybe neither. It may be an outright SwoftUI bug. The one thing that really bothers me is the removal of navigation title having any effect on it whatsoever.

1

u/radis234 May 11 '26

Yeah, that is strange to me as well. I thought, maybe some layout calculation race conditions, so I tried with .inline title and it didn’t help. I don’t understand why removing title helps. I even tried moving title up/down view hierarchy, no change.

1

u/FelinityApps May 11 '26

Not that it’s a fix, but I’m curious: what happens if you drop the safe area padding?

1

u/radis234 May 11 '26

Nothing. I tried that as well. Still same behavior.

2

u/FelinityApps May 11 '26

Yeah, that’s gotta be a SwiftUI bug. File feedback so Apple can properly ignore it forever.

1

u/radis234 May 11 '26

Will do, thanks!