Search code examples
iosswiftuiuikit

SwiftUI/UIKit - Bottom Sheet Drop back on Smaller Detents


I want to know how this effect is achieved in SwiftUI or UIKit. https://streamable.com/hvo8k7

I did some tests using the SwiftUI bottom sheet:

var body: some View {
    Button("Toggle") {
        showingCredits.toggle()
    }
    .sheet(isPresented: $showing) {
        Text("Test sheet")
            .presentationDetents([.medium, .large])
    }
}

The "drop back" only occurs, if the bottom sheet reaches the "large" presentation detend. But my question is how to achieve this "drop back" on different detents but large.


Solution

  • This will work with non-large presentation sheets:

    import SwiftUI
    
    struct ContentView: View {
        
        @State private var showingCredits = false
        
        var body: some View {
            VStack {
                Spacer()
                HStack {
                    Spacer()
                    Button("Toggle") {
                        showingCredits.toggle()
                    }
                    Spacer()
                }
                Spacer()
            }
            .customSheet(isPresented: $showingCredits) {
                Text("Test sheet")
            }
        }
    }
    
    #Preview {
        ContentView()
    }
    
    struct CustomSheet<Destination: View>: ViewModifier {
        
        @Binding var isPresented: Bool
        @ViewBuilder var destination: () -> Destination
        
        @State private var scale: CGSize = CGSize(width: 1.0, height: 1.0)
        @State private var cornerRadius: Double = 0.0
        
        func body(content: Content) -> some View {
            content
                .background(.background)
                .cornerRadius(cornerRadius)
                .scaleEffect(scale)
                .onChange(of: isPresented, { _, newValue in
                    withAnimation {
                        scale = newValue ? CGSize(width: 0.95, height: 0.95) : CGSize(width: 1.0, height: 1.0)
                        cornerRadius = newValue ? 15 : 0
                    }
                })
                .sheet(isPresented: $isPresented) {
                    destination()
                        .presentationDetents([.medium])
                }
                .background(.black)
        }
    }
    
    extension View {
        func customSheet<Destination: View>(isPresented: Binding<Bool>, @ViewBuilder destination: @escaping () -> Destination) -> some View {
            modifier(CustomSheet(isPresented: isPresented, destination: destination))
        }
    }
    

    enter image description here