Dynamic Presentation Sheet Heights

In my application, I have NavigationStack presented as a sheet, and I intend to dynamically adjust its height while pushing views within it. I'm utilizing a global observable variable to manage the height and everything works fine except that the height changes abruptly without any animation. It abruptly transitions from one height to another.

The issue can be reproduced using the following code:

#Preview {
  @Previewable @State var height: CGFloat = 200
  
  Text("Parent View")
    .sheet(isPresented: .constant(true)) {
      NavigationStack {
        Form {
          NavigationLink("Button") {
            RoundedRectangle(cornerRadius: 20)
              .fill(Color.blue)
              .frame(height: 200)
              .navigationTitle("Child")
              .onAppear {
                withAnimation {
                  height = 300
                }
              }
          }
        }
        .navigationTitle("Parent")
        .navigationBarTitleDisplayMode(.inline)
        .presentationDetents([.height(height)])
        .onAppear {
          withAnimation {
            height = 150
          }
        }
      }
    }
}
Answered by alsarraf in 848540022

My issue has been solved on Stack Overflow by Benzy Neez.

struct ContentView: View {
    let detents: Set<PresentationDetent> = [.height(150), .height(300)]
    @State private var selectedDetent: PresentationDetent = .height(150)
    @State private var actualHeight: CGFloat?
    
    var body: some View {
        Text("Parent View")
            .sheet(isPresented: .constant(true)) {
                NavigationStack {
                    Form {
                        NavigationLink("Button") {
                            GeometryReader { proxy in
                                RoundedRectangle(cornerRadius: 20)
                                    .fill(.blue)
                                    .navigationTitle("Child")
                                    .frame(maxHeight: actualHeight)
                                    .animation(.default, value: actualHeight)
                                    .onChange(of: proxy.size.height) { _, newVal in
                                        actualHeight = newVal
                                    }
                            }
                            .onAppear {
                                selectedDetent = .height(300)
                            }
                        }
                    }
                    .navigationTitle("Parent")
                    .navigationBarTitleDisplayMode(.inline)
                    .presentationDetents(detents, selection: $selectedDetent)
                    .onAppear {
                        selectedDetent = .height(150)
                    }
                }
            }
    }
}

Changes to the presentationDetents are animated by default on iOS and custom animations are not yet supported. If you'd like us to consider adding the necessary functionality, please file an enhancement request using Feedback Assistant. Once you file the request, please post the FB number here. If you're not familiar with how to file enhancement requests, take a look at Bug Reporting: How and Why?

Changes to the presentationDetents are animated by default on iOS and custom animations are not yet supported. If you'd like us to consider adding the necessary functionality, please file an enhancement request using Feedback Assistant.

I'm not attempting to create custom animations. My issue is that presentationDetents is not animated despite using a built-in API provided by Apple without any workarounds.

Accepted Answer

My issue has been solved on Stack Overflow by Benzy Neez.

struct ContentView: View {
    let detents: Set<PresentationDetent> = [.height(150), .height(300)]
    @State private var selectedDetent: PresentationDetent = .height(150)
    @State private var actualHeight: CGFloat?
    
    var body: some View {
        Text("Parent View")
            .sheet(isPresented: .constant(true)) {
                NavigationStack {
                    Form {
                        NavigationLink("Button") {
                            GeometryReader { proxy in
                                RoundedRectangle(cornerRadius: 20)
                                    .fill(.blue)
                                    .navigationTitle("Child")
                                    .frame(maxHeight: actualHeight)
                                    .animation(.default, value: actualHeight)
                                    .onChange(of: proxy.size.height) { _, newVal in
                                        actualHeight = newVal
                                    }
                            }
                            .onAppear {
                                selectedDetent = .height(300)
                            }
                        }
                    }
                    .navigationTitle("Parent")
                    .navigationBarTitleDisplayMode(.inline)
                    .presentationDetents(detents, selection: $selectedDetent)
                    .onAppear {
                        selectedDetent = .height(150)
                    }
                }
            }
    }
}
Dynamic Presentation Sheet Heights
 
 
Q