是否可以在SwiftUI中使模式成为不可消除的?

时间:2019-08-07 16:02:08

标签: swiftui

我正在创建一个应用程序,其中登录/注册部分位于模式内部,如果用户未登录,则会显示该模式。

问题是,用户可以通过向下滑动模式来消除该模式...

是否可以防止这种情况?

var body: some View {
    TabView(selection: $selection) {
        App()
    }.sheet(isPresented: self.$showSheet) { // This needs to be non-dismissible
        LoginRegister()
    }
}

第二个示例:

我正在使用模式询问信息。除非通过使用“保存”按钮关闭模态,否则用户不能退出该过程。用户必须在按钮起作用之前输入信息。不幸的是,可以通过向下滑动来消除模态。

是否可以防止这种情况?

5 个答案:

答案 0 :(得分:5)

您可以尝试使用highPriorityGesture来执行此操作。当然,蓝色矩形仅用于演示,但是您必须使用覆盖整个屏幕的视图。

struct ModalViewNoClose : View {
    @Environment(\.presentationMode) var presentationMode

    let gesture = DragGesture()

    var body: some View {

        Rectangle()
            .fill(Color.blue)
            .frame(width: 300, height: 600)
            .highPriorityGesture(gesture)

            .overlay(
                VStack{
                    Button("Close") {
                        self.presentationMode.value.dismiss()
                    }.accentColor(.white)
                    Text("Modal")
                        .highPriorityGesture(gesture)
                    TextField("as", text: .constant("sdf"))
                        .highPriorityGesture(gesture)
                } .highPriorityGesture(gesture)
        )
            .border(Color.green)
    }
}

答案 1 :(得分:3)

这是一个常见的问题,是一种“代码异味” ...并不是真正的代码,而是一种“设计模式异味”。

问题在于您正在使登录过程成为应用程序其余部分的一部分。

您应该真正显示LoginRegisterApp,而不是在App上方显示LoginRegister

即您应该有一些状态对象,例如userLoggedIn: Bool或其他内容,并根据该值显示AppLoginRegister

仅在同一时间不在视图层次结构中。这样,您的用户将无法关闭视图。

答案 2 :(得分:1)

iOS 15

从 iOS 15 开始,您可以使用 interactiveDismissDisabled

您只需要将其附加到工作表上:

var body: some View {
    TabView(selection: $selection) {
        App()
    }.sheet(isPresented: self.$showSheet) {
        LoginRegister()
            .interactiveDismissDisabled(true)
    }
}

关于你的第二个例子,你可以传递一个变量来控制何时禁用工作表:

.interactiveDismissDisabled(!isAllInformationProvided)

您可以在 documentation 中找到更多信息。

答案 3 :(得分:0)

如果您不介意使用Introspect

import Introspect

@available(iOS 13, *)
extension View {
    /// A Boolean value indicating whether the view controller enforces a modal behavior.
    ///
    /// The default value of this property is `false`. When you set it to `true`, UIKit ignores events
    /// outside the view controller's bounds and prevents the interactive dismissal of the
    /// view controller while it is onscreen.
    public func isModalInPresentation(_ value: Bool) -> some View {
        introspectViewController {
            $0.isModalInPresentation = value
        }
    }
}

用法:

.sheet {
    VStack {
        ...
    }.isModalInPresentation(true)
}

答案 4 :(得分:0)

从理论上讲,这可能会对您有所帮助(我没有尝试过)

private var isDisplayedBind: Binding<Bool>{ Binding(get: { true }, set: { _ = $0 }) }

和用法:

content
    .sheet(isPresented: isDisplayedBind) { some sheet }