swiftswiftuiviewsize

SwiftUI: How to set the size of a SHEET, but leave ist draggable at the same time


I have a simple sheet on a view. The sheet has a specific height right from the start, but it is draggable for the user to the height .medium and .large.

On the sheet is a button. When the button is tagged, the sheet is supposed to be shown in a new height. After, the user kann drag the sheet as he could before.

THE PROBLEM: I can define the heights to which the user can drag the sheet by using .presentationDetents([.height(40), .medium, .large]). But I don't arrive to set the sheet on a specific height(e.g. 200).

When I define a custom height like .presentationDetents([.height(200)]), it sets the sheet on 200. BUT it is no more draggable for the user, as I had to eliminate the other heights (.medium and .large).

Here is my code:

import SwiftUI

struct ContentView: View {
    @State private var sheetSize: Float = 60
    var body: some View {
        
        Text("Hello")
            
            .sheet(isPresented: .constant(true)) {
                
                Button {
                    if sheetSize == 40 {
                        sheetSize = 200     // THIS DOES NOT WORK.
                    }
                    else {
                        sheetSize = 60
                    }
                    
                    print("sheetSize:", sheetSize)
                } label: {
                    Image(systemName: "button.programmable")
                        .font(.largeTitle)
                        .frame(maxWidth: .infinity, alignment: .center)
                }
                
                .presentationDetents([.height(CGFloat(sheetSize)), .medium, .large])
                .interactiveDismissDisabled()
                .presentationDragIndicator(.visible)
                
                
                
            } // Sheet
                
                    
    }// var body
}// struct


#Preview {
    ContentView()
}

Solution

  • Pass a Binding<PresentationDetent> the selection parameter to programmatically change the detent.

    Here I have added a new @State called currentDetent to track the current detent. You should set it, in addition to setting sheetSize in the button's action.

    @State private var sheetSize: CGFloat = 60
    @State private var currentDetent = PresentationDetent.height(60)
    var body: some View {
        
        Text("Hello")
        
            .sheet(isPresented: .constant(true)) {
                
                Button {
                    if sheetSize == 60 {
                        sheetSize = 200
                        currentDetent = .height(200)
                    } else {
                        sheetSize = 60
                        currentDetent = .height(60)
                    }
                    
                    print("sheetSize:", sheetSize)
                } label: {
                    Image(systemName: "button.programmable")
                        .font(.largeTitle)
                        .frame(maxWidth: .infinity, alignment: .center)
                }
                
                .presentationDetents([.height(sheetSize), .medium, .large], selection: $currentDetent)
                .interactiveDismissDisabled()
                .presentationDragIndicator(.visible)
            }
    }