SwiftUI - in sheet have a fixed continue button that is not scrollable

前端 未结 2 871
别跟我提以往
别跟我提以往 2020-12-10 23:21

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

相关标签:
2条回答
  • 2020-12-10 23:48

    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()
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-10 23:48

    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...

    0 讨论(0)
提交回复
热议问题