Last active
March 27, 2025 03:25
-
-
Save dankamel/d7d66bea734ff1a2ea2a6f6abfd538ad to your computer and use it in GitHub Desktop.
Native iOS 15 Adjustable Bottom Sheet In SwiftUI (half bottom sheet)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct BottomSheetDesign: View { | |
@State var showSheet: Bool? = nil | |
var body: some View { | |
Button(action: { showSheet = true }) { | |
HStack (spacing: 5) { | |
Image(systemName: "hand.tap.fill") | |
.font(.system(size: 20, weight: .regular, design: .rounded)) | |
Text("me to bring up adjustable sheet") | |
.font(.system(size: 20, weight: .regular, design: .rounded)) | |
} | |
} | |
.halfSheet(showSheet: $showSheet) { | |
ZStack { | |
Color.blue | |
ScrollView(.vertical, showsIndicators: false) { | |
VStack { | |
RoundedRectangle(cornerRadius: 12, style: .continuous) | |
.frame(width: 50, height: 8) | |
.padding(.top, -20) | |
.foregroundColor(.black.opacity(0.2)) | |
Text("Hello half sheet 🥹") | |
.font(.system(size: 25, weight: .regular, design: .rounded)) | |
.foregroundColor(.white) | |
.padding(.top, 70) | |
.padding(.bottom, 10) | |
Button(action: { showSheet = false }) { | |
HStack(spacing: 5) { | |
Image(systemName: "hand.tap.fill") | |
.font(.system(size: 20, weight: .bold, design: .rounded)) | |
.foregroundColor(.white) | |
Text("me to close sheet") | |
.font(.system(size: 20, weight: .bold, design: .rounded)) | |
.foregroundColor(.white) | |
} | |
} | |
} | |
.padding(.top, 30) | |
} | |
} | |
.edgesIgnoringSafeArea(.bottom) | |
} onDismiss: { | |
print("sheet dismissed") | |
} | |
} | |
} | |
struct BottomSheetDesign_Previews: PreviewProvider { | |
static var previews: some View { | |
BottomSheetDesign() | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
// Custom Half Sheet Modifier.... | |
extension View { | |
//binding show bariable... | |
func halfSheet<Content: View>( | |
showSheet: Binding<Bool?>, | |
@ViewBuilder content: @escaping () -> Content, | |
onDismiss: @escaping () -> Void | |
) -> some View { | |
return self | |
.background( | |
HalfSheetHelper(sheetView: content(), showSheet: showSheet, onDismiss: onDismiss) | |
) | |
} | |
} | |
// UIKit integration | |
struct HalfSheetHelper<Content: View>: UIViewControllerRepresentable { | |
var sheetView: Content | |
let controller: UIViewController = UIViewController() | |
@Binding var showSheet: Bool? | |
var onDismiss: () -> Void | |
func makeCoordinator() -> Coordinator { | |
Coordinator(parent: self) | |
} | |
func makeUIViewController(context: Context) -> UIViewController { | |
controller.view.backgroundColor = .clear | |
return controller | |
} | |
func updateUIViewController(_ uiViewController: UIViewController, context: Context) { | |
if let showSheet: Bool = showSheet { | |
if showSheet { | |
let sheetController = CustomHostingController(rootView: sheetView) | |
sheetController.presentationController?.delegate = context.coordinator | |
uiViewController.present(sheetController, animated: true) | |
} | |
} | |
} | |
//on dismiss... | |
final class Coordinator: NSObject, UISheetPresentationControllerDelegate { | |
var parent: HalfSheetHelper | |
init(parent: HalfSheetHelper) { | |
self.parent = parent | |
} | |
func presentationControllerWillDismiss(_ presentationController: UIPresentationController) { | |
parent.showSheet = false | |
} | |
} | |
} | |
// Custom UIHostingController for halfSheet... | |
final class CustomHostingController<Content: View>: UIHostingController<Content> { | |
override func viewDidLoad() { | |
view.backgroundColor = .clear | |
if let presentationController = presentationController as? UISheetPresentationController { | |
presentationController.detents = [ | |
.medium(), | |
.large() | |
] | |
//MARK: - sheet grabber visbility | |
presentationController.prefersGrabberVisible = false // i wanted to design my own grabber hehehe | |
// this allows you to scroll even during medium detent | |
presentationController.prefersScrollingExpandsWhenScrolledToEdge = false | |
//MARK: - sheet corner radius | |
presentationController.preferredCornerRadius = 30 | |
// for more sheet customisation check out this great article https://sarunw.com/posts/bottom-sheet-in-ios-15-with-uisheetpresentationcontroller/#scrolling | |
} | |
} | |
} | |
public struct LazyView<Content: View>: View { | |
private let build: () -> Content | |
public init(_ build: @autoclosure @escaping () -> Content) { | |
self.build = build | |
} | |
public var body: Content { | |
build() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
But its not properly working in ipad.It does not completely occupy the whole width.So If you have any solution for this,kindly let me know.