As you can see even though I am trying to pull the sheet down, the continue button does not move down. How can I make my sheet to behave like that? In my app the con
Here is a demo of possible approach (tuning & effects are out of scope - try to make demo code short). The idea is to inject UIView
holder with button above sheet so it persist during sheet drag down (because as findings shown any dynamic offsets gives some ugly undesired shaking effects).
Tested with Xcode 12 / iOS 14
// ... your above code here
}//VStack for 3 criterias
.padding([.leading, .trailing], 20)
Spacer()
// button moved from here into below background view !!
}.background(BottomView(presentation: presentationMode) {
Button {
presentationMode.wrappedValue.dismiss()
UserDefaults.standard.set(true, forKey: "LaunchedBefore")
} label: {
Text("Continue")
.fontWeight(.medium)
.padding([.top, .bottom], 15)
.padding([.leading, .trailing], 90)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(15)
}
})
//Main VStack
}
}
struct BottomView<Content: View>: UIViewRepresentable {
@Binding var presentationMode: PresentationMode
private var content: () -> Content
init(presentation: Binding<PresentationMode>, @ViewBuilder _ content: @escaping () -> Content) {
_presentationMode = presentation
self.content = content
}
func makeUIView(context: Context) -> UIView {
let view = UIView()
DispatchQueue.main.async {
if let window = view.window {
let holder = UIView()
context.coordinator.holder = holder
// simple demo background to make it visible
holder.layer.backgroundColor = UIColor.gray.withAlphaComponent(0.5).cgColor
holder.translatesAutoresizingMaskIntoConstraints = false
window.addSubview(holder)
holder.heightAnchor.constraint(equalToConstant: 140).isActive = true
holder.bottomAnchor.constraint(equalTo: window.bottomAnchor, constant: 0).isActive = true
holder.leadingAnchor.constraint(equalTo: window.leadingAnchor, constant: 0).isActive = true
holder.trailingAnchor.constraint(equalTo: window.trailingAnchor, constant: 0).isActive = true
if let contentView = UIHostingController(rootView: content()).view {
contentView.backgroundColor = UIColor.clear
contentView.translatesAutoresizingMaskIntoConstraints = false
holder.addSubview(contentView)
contentView.topAnchor.constraint(equalTo: holder.topAnchor, constant: 0).isActive = true
contentView.bottomAnchor.constraint(equalTo: holder.bottomAnchor, constant: 0).isActive = true
contentView.leadingAnchor.constraint(equalTo: holder.leadingAnchor, constant: 0).isActive = true
contentView.trailingAnchor.constraint(equalTo: holder.trailingAnchor, constant: 0).isActive = true
}
}
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
if !presentationMode.isPresented {
context.coordinator.holder.removeFromSuperview()
}
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator {
var holder: UIView!
deinit {
holder.removeFromSuperview()
}
}
}
Simply add that :
.sheet(isPresented: self.$visibleSheet) {
IntroView(visibleSheet: self.$visibleSheet)
.presentation(shouldDismissOnDrag: false)
}
https://stackoverflow.com/a/61239704/7974174 :
extension View {
func presentation(shouldDismissOnDrag: Bool, onDismissalAttempt: (()->())? = nil) -> some View {
ModalView(view: self, shouldDismiss: shouldDismissOnDrag, onDismissalAttempt: onDismissalAttempt)
}
}
struct ModalView<T: View>: UIViewControllerRepresentable {
let view: T
let shouldDismiss: Bool
let onDismissalAttempt: (()->())?
func makeUIViewController(context: Context) -> UIHostingController<T> {
UIHostingController(rootView: view)
}
func updateUIViewController(_ uiViewController: UIHostingController<T>, context: Context) {
uiViewController.parent?.presentationController?.delegate = context.coordinator
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UIAdaptivePresentationControllerDelegate {
let modalView: ModalView
init(_ modalView: ModalView) {
self.modalView = modalView
}
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
modalView.shouldDismiss
}
func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
modalView.onDismissalAttempt?()
}
}
}
It disables the sheet closing by dragging the sheet down. If you want to close the sheet with the button do not use presentationMode
anymore. Pass a binding of self.$visibleSheet
then modify to false from inside...