Created
March 22, 2022 17:31
-
-
Save sean-perkins/389d7f3445538edbe90441b283bd43ff to your computer and use it in GitHub Desktop.
iOS Modal Sheet (SwfitUI)
This file contains 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
// | |
// ContentView.swift | |
// bottom-sheet | |
// | |
// Created by Sean Perkins on 3/22/22. | |
// | |
import SwiftUI | |
struct ContentView: View { | |
var body: some View { | |
Home() | |
} | |
} | |
struct ContentView_Previews: PreviewProvider { | |
static var previews: some View { | |
ContentView() | |
} | |
} | |
struct Home: View { | |
@State var showSheet: Bool = false | |
var body: some View { | |
NavigationView { | |
Button { | |
showSheet.toggle() | |
} label: { | |
Text("Present Sheet") | |
} | |
.navigationTitle("Modal Sheet") | |
.halfSheet(showSheet: $showSheet) { | |
ZStack { | |
Color.red | |
VStack { | |
Text("Hello World") | |
.font(.title.bold()) | |
.foregroundColor(.white) | |
Button { | |
showSheet.toggle() | |
} label: { | |
Text("Dismiss") | |
.foregroundColor(.white) | |
} | |
.padding() | |
} | |
} | |
.ignoresSafeArea() | |
} onEnd: { | |
print("Dismissed") | |
} | |
} | |
} | |
} | |
extension View { | |
func halfSheet<SheetView: View>(showSheet: Binding<Bool>, @ViewBuilder sheetView: @escaping ()->SheetView, onEnd: @escaping ()->())->some View { | |
return self | |
.background( | |
HalfSheetHelper(sheetView: sheetView(), showSheet: showSheet, onEnd: onEnd) | |
) | |
} | |
} | |
struct HalfSheetHelper<SheetView: View>: UIViewControllerRepresentable { | |
var sheetView: SheetView | |
@Binding var showSheet: Bool | |
var onEnd: () ->() | |
let controller = UIViewController() | |
func makeCoordinator()-> Coordinator { | |
return Coordinator(parent: self) | |
} | |
func makeUIViewController(context: Context) -> UIViewController { | |
controller.view.backgroundColor = .clear | |
return controller | |
} | |
func updateUIViewController(_ uiViewControlller: UIViewController, context: Context) { | |
if showSheet { | |
let sheetController = CustomHostingController(rootView: sheetView) | |
sheetController.presentationController?.delegate = context.coordinator | |
uiViewControlller.present(sheetController, animated: true) | |
} else { | |
uiViewControlller.dismiss(animated: true) | |
} | |
} | |
class Coordinator: NSObject, UISheetPresentationControllerDelegate { | |
var parent: HalfSheetHelper | |
init (parent: HalfSheetHelper) { | |
self.parent = parent | |
} | |
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { | |
parent.showSheet = false | |
parent.onEnd() | |
} | |
} | |
} | |
class CustomHostingController<Content: View>: UIHostingController<Content> { | |
override func viewDidLoad() { | |
view.backgroundColor = .clear | |
if let presentationController = presentationController as? UISheetPresentationController { | |
presentationController.detents = [ | |
.medium(), | |
.large() | |
] | |
presentationController.prefersGrabberVisible = true | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment