是否可以在 SwiftUI 中设置不可关闭的模态?
Is it possible to make a modal non-dismissible in SwiftUI?
我正在创建一个应用程序,其中登录/注册部分位于模式内,如果用户未登录则显示。
问题是,用户可以通过向下滑动来关闭模式...
是否可以避免这种情况?
var body: some View {
TabView(selection: $selection) {
App()
}.sheet(isPresented: self.$showSheet) { // This needs to be non-dismissible
LoginRegister()
}
}
第二个例子:
我正在使用模式来询问信息。除非使用保存按钮关闭模态,否则用户不应该能够退出此过程。用户必须在按钮工作之前输入信息。不幸的是,可以通过向下滑动来关闭模态。
是否可以避免这种情况?
这是一个常见问题,"code smell"...好吧,这不是真正的代码,而是 "design pattern smell"。
问题是您将登录过程作为应用程序其余部分的一部分。
与其在 App
上显示 LoginRegister
,不如显示 App
或 LoginRegister
。
即你应该有一些像 userLoggedIn: Bool
之类的状态对象,并且根据该值你应该显示 App
或 LoginRegister
.
只是不要同时在视图层次结构中。这样您的用户将无法关闭视图。
iOS 15 岁及以后:
在sheet上使用.interactiveDismissDisabled(true)
,仅此而已。
上一页 iOS 15:
您可以尝试使用 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)
}
}
如果您不介意使用 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 {
[=10=].isModalInPresentation = value
}
}
}
用法:
.sheet {
VStack {
...
}.isModalInPresentation(true)
}
理论上这可能对你有帮助(我没试过)
private var isDisplayedBind: Binding<Bool>{ Binding(get: { true }, set: { _ = [=10=] }) }
和用法:
content
.sheet(isPresented: isDisplayedBind) { some sheet }
iOS 15
从 iOS 15 开始,您可以使用 interactiveDismissDisabled
。
您只需将其附加到 sheet:
var body: some View {
TabView(selection: $selection) {
App()
}.sheet(isPresented: self.$showSheet) {
LoginRegister()
.interactiveDismissDisabled(true)
}
}
关于您的第二个示例,您可以传递一个变量来控制何时禁用 sheet:
.interactiveDismissDisabled(!isAllInformationProvided)
您可以在 documentation 中找到更多信息。
我正在创建一个应用程序,其中登录/注册部分位于模式内,如果用户未登录则显示。
问题是,用户可以通过向下滑动来关闭模式...
是否可以避免这种情况?
var body: some View {
TabView(selection: $selection) {
App()
}.sheet(isPresented: self.$showSheet) { // This needs to be non-dismissible
LoginRegister()
}
}
第二个例子:
我正在使用模式来询问信息。除非使用保存按钮关闭模态,否则用户不应该能够退出此过程。用户必须在按钮工作之前输入信息。不幸的是,可以通过向下滑动来关闭模态。
是否可以避免这种情况?
这是一个常见问题,"code smell"...好吧,这不是真正的代码,而是 "design pattern smell"。
问题是您将登录过程作为应用程序其余部分的一部分。
与其在 App
上显示 LoginRegister
,不如显示 App
或 LoginRegister
。
即你应该有一些像 userLoggedIn: Bool
之类的状态对象,并且根据该值你应该显示 App
或 LoginRegister
.
只是不要同时在视图层次结构中。这样您的用户将无法关闭视图。
iOS 15 岁及以后:
在sheet上使用.interactiveDismissDisabled(true)
,仅此而已。
上一页 iOS 15:
您可以尝试使用 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)
}
}
如果您不介意使用 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 {
[=10=].isModalInPresentation = value
}
}
}
用法:
.sheet {
VStack {
...
}.isModalInPresentation(true)
}
理论上这可能对你有帮助(我没试过)
private var isDisplayedBind: Binding<Bool>{ Binding(get: { true }, set: { _ = [=10=] }) }
和用法:
content
.sheet(isPresented: isDisplayedBind) { some sheet }
iOS 15
从 iOS 15 开始,您可以使用 interactiveDismissDisabled
。
您只需将其附加到 sheet:
var body: some View {
TabView(selection: $selection) {
App()
}.sheet(isPresented: self.$showSheet) {
LoginRegister()
.interactiveDismissDisabled(true)
}
}
关于您的第二个示例,您可以传递一个变量来控制何时禁用 sheet:
.interactiveDismissDisabled(!isAllInformationProvided)
您可以在 documentation 中找到更多信息。