Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/108.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 防止在SwiftUI中取消模态视图控制器_Ios_Swift_Swiftui - Fatal编程技术网

Ios 防止在SwiftUI中取消模态视图控制器

Ios 防止在SwiftUI中取消模态视图控制器,ios,swift,swiftui,Ios,Swift,Swiftui,在2019年WWDC大会上,苹果宣布了一种新的模态演示“卡片式”外观,该外观附带了内置手势,可通过向下滑动卡片来解除模态视图控制器。他们还在UIViewController上引入了新的isModalInPresentation属性,以便您可以在选择的情况下禁止这种解雇行为 不过,到目前为止,我还没有找到在SwiftUI中模仿这种行为的方法。据我所知,使用.presentation(u.modal:modal?)不允许您以相同的方式禁用解雇手势。我还尝试将模态视图控制器放入UIViewContro

在2019年WWDC大会上,苹果宣布了一种新的模态演示“卡片式”外观,该外观附带了内置手势,可通过向下滑动卡片来解除模态视图控制器。他们还在
UIViewController
上引入了新的
isModalInPresentation
属性,以便您可以在选择的情况下禁止这种解雇行为

不过,到目前为止,我还没有找到在SwiftUI中模仿这种行为的方法。据我所知,使用
.presentation(u.modal:modal?
)不允许您以相同的方式禁用解雇手势。我还尝试将模态视图控制器放入
UIViewControllerRepresentable
视图
,但这似乎也没有帮助:

struct MyViewControllerView: UIViewControllerRepresentable {
    func makeUIViewController(context: UIViewControllerRepresentableContext<MyViewControllerView>) -> UIHostingController<MyView> {
        return UIHostingController(rootView: MyView())
    }

    func updateUIViewController(_ uiViewController: UIHostingController<MyView>, context: UIViewControllerRepresentableContext<MyViewControllerView>) {
        uiViewController.isModalInPresentation = true
    }
}
struct MyViewControllerView:UIViewControllerRepresentable{
func makeUIViewController(上下文:UIViewControllerRepresentableContext)->UIHostingController{
返回UIHostingController(rootView:MyView())
}
func updateUIViewController(uViewController:UIHostingController,上下文:UIViewControllerRepresentableContext){
uiViewController.isModalInPresentation=true
}
}

即使在使用
.presentation(Modal(MyViewControllerView())
演示之后,我仍然能够向下滑动以关闭视图。当前是否有任何方法可以使用现有的SwiftUI构造实现这一点?

通过更改不希望拖动的任何视图的
手势优先级
,可以阻止任何视图上的
拖动。例如,对于Modal,可按以下方式进行:

也许这不是一个最佳实践,但它非常有效

struct ContentView: View {

@State var showModal = true

var body: some View {

    Button(action: {
        self.showModal.toggle()

    }) {
        Text("Show Modal")
    }.sheet(isPresented: self.$showModal) {
        ModalView()
    }
  }
}


注意:为了清晰和简洁,对该代码进行了编辑

使用从中获取当前窗口场景的方法,可以通过此扩展从中获取俯视图控制器

并将其转换为视图修改器,如下所示:

struct DisableModalDismiss: ViewModifier {
    let disabled: Bool
    func body(content: Content) -> some View {
        disableModalDismiss()
        return AnyView(content)
    }

    func disableModalDismiss() {
        guard let visibleController = UIApplication.shared.visibleViewController() else { return }
        visibleController.isModalInPresentation = disabled
    }
}
并使用类似于:

struct ShowSheetView: View {
    @State private var showSheet = true
    var body: some View {
        Text("Hello, World!")
        .sheet(isPresented: $showSheet) {
            TestView()
                .modifier(DisableModalDismiss(disabled: true))
        }
    }
}
iOS 15的更新 根据下面的,新的
interactiveDismissDisabled(:)
API现在支持这一点

struct ContentView:View{
@国家私有var显示表=false
var body:一些观点{
文本(“内容视图”)
.sheet(显示:$showSheet){
文本(“图纸视图”)
.interactiveDismissDisabled(真)
}
}
}
iOS-15之前的答案 我也想这样做,但在任何地方都找不到解决方案。劫持拖动手势的答案是可行的,但当它通过滚动滚动视图或表单而被取消时就不行了。问题中的方法也不太老套,所以我进一步研究了它

对于我的用例,我有一个表单,理想情况下,当没有内容时可以将其删除,但当有内容时必须通过警报进行确认

我对此问题的解决方案:

struct ModalSheetTest:视图{
@State private var showModally=false
@国家私有var显示表=false
var body:一些观点{
形式{
切换(isOn:self.$showmodly){
文本(“模态”)
}
按钮(操作:{self.showSheet=true}){
文本(“显示页”)
}
}
.sheet(显示:$showSheet){
形式{
按钮(操作:{self.showSheet=false}){
文本(“隐藏我”)
}
}
.presentation(isModal:self.showmodly){
打印(“试图驳回”)
}
}
}
}
状态值
showmodly
确定是否必须以模式显示。如果是这样,将其向下拖动到Disclose只会触发关闭,该关闭在示例中仅打印“试图解除”,但可用于显示确认解除的警报

struct ModalView:UIViewControllerRepresentable{
让我们来看一看:T
让伊斯莫达尔:布尔
让我们试一下:(()->())?
func makeUIViewController(上下文:context)->UIHostingController{
UIHostingController(根视图:视图)
}
func updateUIViewController(uViewController:UIHostingController,上下文:上下文){
context.coordinator.modalView=self
uiViewController.rootView=视图
uiViewController.parent?.presentationController?.delegate=context.coordinator
}
func makeCoordinator()->Coordinator{
协调员(自我)
}
类协调器:NSObject,UIAdaptivePresentationControllerDelegate{
让莫达维:莫达维
init(modalView:modalView){
self.modalView=modalView
}
func presentationController应关闭(presentationController:UIPresentationController)->Bool{
!modalView.isModal
}
func presentationController DidAttemptToDismiss(presentationController:UIPresentationController){
modalView.Ondismissalatter?()
}
}
}
扩展视图{
函数表示(isModal:Bool,ONDISMISSALATTENT:(()->())?=nil)->一些视图{
ModalView(视图:self、isModal:isModal、ondisIsSalattest:ondisIsSalattest)
}
}

这非常适合我的用例,希望它也能帮助您或其他人。

我们已经创建了一个扩展,可以轻松地控制模式解除,至少


可以使用此方法传递模态视图的内容以供重用

使用具有
手势优先级的NavigationView来禁用
拖动

import SwiftUI

struct ModalView<Content: View>: View
{
    @Environment(\.presentationMode) var presentationMode
    let content: Content
    let title: String
    let dg = DragGesture()
    
    init(title: String, @ViewBuilder content: @escaping () -> Content) {
        self.content = content()
        self.title = title
    }
    
    var body: some View
    {
        NavigationView
        {
            ZStack (alignment: .top)
            {
                self.content
            }
            .navigationBarTitleDisplayMode(.inline)
            .toolbar(content: {
                ToolbarItem(placement: .principal, content: {
                    Text(title)
                })
                
                ToolbarItem(placement: .navigationBarTrailing, content: {
                    Button("Done") {
                        self.presentationMode.wrappedValue.dismiss()
                    }
                })
            })
        }
        .highPriorityGesture(dg)
    }
}
结果


这个解决方案在iPhone和iPad上对我很有效。它使用
isModalInPresentation
。发件人:

此属性的默认值为false。将其设置为true时,UIKit将忽略视图控制器边界之外的事件,并防止视图控制器在屏幕上时被交互式取消

你的尝试接近于我的成功。诀窍在于设置
struct ShowSheetView: View {
    @State private var showSheet = true
    var body: some View {
        Text("Hello, World!")
        .sheet(isPresented: $showSheet) {
            TestView()
                .modifier(DisableModalDismiss(disabled: true))
        }
    }
}
/// Example:
struct ContentView: View {
    @State private var presenting = false
    
    var body: some View {
        VStack {
            Button {
                presenting = true
            } label: {
                Text("Present")
            }
        }
        .sheet(isPresented: $presenting) {
            ModalContent()
                .allowAutoDismiss { false }
                // or
                // .allowAutoDismiss(false)
        }
    }
}
import SwiftUI

struct ModalView<Content: View>: View
{
    @Environment(\.presentationMode) var presentationMode
    let content: Content
    let title: String
    let dg = DragGesture()
    
    init(title: String, @ViewBuilder content: @escaping () -> Content) {
        self.content = content()
        self.title = title
    }
    
    var body: some View
    {
        NavigationView
        {
            ZStack (alignment: .top)
            {
                self.content
            }
            .navigationBarTitleDisplayMode(.inline)
            .toolbar(content: {
                ToolbarItem(placement: .principal, content: {
                    Text(title)
                })
                
                ToolbarItem(placement: .navigationBarTrailing, content: {
                    Button("Done") {
                        self.presentationMode.wrappedValue.dismiss()
                    }
                })
            })
        }
        .highPriorityGesture(dg)
    }
}
struct ContentView: View {

@State var showModal = true

var body: some View {

    Button(action: {
       self.showModal.toggle()
    }) {
       Text("Show Modal")
    }.sheet(isPresented: self.$showModal) {
       ModalView (title: "Title") {
          Text("Prevent dismissal of modal view.")
       }
    }
  }
}
class MyHostingController<Content: View>: UIHostingController<Content> {
    var canDismissSheet = true

    override func willMove(toParent parent: UIViewController?) {
        super.willMove(toParent: parent)
        parent?.isModalInPresentation = !canDismissSheet
    }
}

struct MyViewControllerView<Content: View>: UIViewControllerRepresentable {
    let content: Content
    let canDismissSheet: Bool

    func makeUIViewController(context: Context) -> UIHostingController<Content> {
        let viewController = MyHostingController(rootView: content)
        viewController.canDismissSheet = canDismissSheet
        return viewController
    }

    func updateUIViewController(_ uiViewController: UIHostingController<Content>, context: Context) {
        uiViewController.parent?.isModalInPresentation = !canDismissSheet
    }
}
struct FullScreenCoverPresenterView: View {
    @State private var isPresenting = false

    var body: some View {
        Button("Present Full-Screen Cover") {
            isPresenting.toggle()
        }
        .fullScreenCover(isPresented: $isPresenting) {
            Text("Tap to Dismiss")
                .onTapGesture {
                    isPresenting.toggle()
                }
        }
    }
}
func interactiveDismissDisabled(_ isDisabled: Bool = true) -> some View
struct ContentView: View {
    @State private var showSheet = false

    var body: some View {
        Text("Content View")
            .sheet(isPresented: $showSheet) {
                Text("Sheet View")
                    .interactiveDismissDisabled(true)
            }
    }
}
.interactiveDismissDisabled(!userAcceptedTermsOfUse)