I'm trying to recreate a Modal just like Safari in iOS13 in SwiftUI:
Here's what it looks like:
Does anyone know if this is possible in SwiftUI? I want to show a small half modal, with the option to drag to fullscreen, just like the sharing sheet.
Any advice is much appreciated!
Starting from iOS 16, the SwiftUI framework comes with a new modifier called presentationDetents for presenting a resizable bottom sheet. Text("This is the expandable bottom sheet." You specify a set of detents in the presentationDetents modifier. As shown above, the bottom sheet supports both medium and large size.
To use a sheet, give it something to show (some text, an image, a custom view, etc), add a Boolean that defines whether the detail view should be showing, then attach it to your main view as a modal sheet. Important: If you're targeting iOS 14 or below, you should use @Environment(\.
I've written a Swift Package that includes a custom modifier that allows you to use the half modal sheet.
Here is the link: https://github.com/AndreaMiotto/PartialSheet
Feel free to use it or to contribute
You can make your own and place it inside of a zstack: https://www.mozzafiller.com/posts/swiftui-slide-over-card-like-maps-stocks
struct SlideOverCard<Content: View> : View { @GestureState private var dragState = DragState.inactive @State var position = CardPosition.top var content: () -> Content var body: some View { let drag = DragGesture() .updating($dragState) { drag, state, transaction in state = .dragging(translation: drag.translation) } .onEnded(onDragEnded) return Group { Handle() self.content() } .frame(height: UIScreen.main.bounds.height) .background(Color.white) .cornerRadius(10.0) .shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0) .offset(y: self.position.rawValue + self.dragState.translation.height) .animation(self.dragState.isDragging ? nil : .spring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0)) .gesture(drag) } private func onDragEnded(drag: DragGesture.Value) { let verticalDirection = drag.predictedEndLocation.y - drag.location.y let cardTopEdgeLocation = self.position.rawValue + drag.translation.height let positionAbove: CardPosition let positionBelow: CardPosition let closestPosition: CardPosition if cardTopEdgeLocation <= CardPosition.middle.rawValue { positionAbove = .top positionBelow = .middle } else { positionAbove = .middle positionBelow = .bottom } if (cardTopEdgeLocation - positionAbove.rawValue) < (positionBelow.rawValue - cardTopEdgeLocation) { closestPosition = positionAbove } else { closestPosition = positionBelow } if verticalDirection > 0 { self.position = positionBelow } else if verticalDirection < 0 { self.position = positionAbove } else { self.position = closestPosition } } } enum CardPosition: CGFloat { case top = 100 case middle = 500 case bottom = 850 } enum DragState { case inactive case dragging(translation: CGSize) var translation: CGSize { switch self { case .inactive: return .zero case .dragging(let translation): return translation } } var isDragging: Bool { switch self { case .inactive: return false case .dragging: return true } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With