我有一个 SwiftUI 应用程序,带有复杂的仪表板视图,其中包含其他几个包含 SwiftUI 按钮的嵌套自定义 SwiftUI 视图。
我想防止用多个手指同时按下这些不同的按钮并同时执行它们的操作,这目前是可能的。
我还找不到任何对我有用的解决方案。例如。在这个SO问题中(如何防止在swiftUI中同时点击两个按钮?)有两种解决方案:
在仪表板视图的
multitouch
中禁用 exclusiveTouch
并启用 init
:
UIButton.appearance().isMultipleTouchEnabled = false
UIButton.appearance().isExclusiveTouch = true
UIView.appearance().isMultipleTouchEnabled = false
UIView.appearance().isExclusiveTouch = true
这对我来说绝对不起作用,无论是在视图的
init
中,还是当我将其全局放在 @main
init 或应用程序的其他全局入口点中时。
isEnabled
状态,并在每次按下按钮时切换它,并将所有其他按钮设置为 disabled
。但这个解决方案对我来说不起作用,因为实际的 SwiftUI 按钮部分嵌套在其他视图的多个层中。我无法理解,这在 SwiftUI 中是一个很大的痛苦。以某种方式应该可以防止同时按下多个按钮。
还有其他解决办法吗?
如果您利用
EnvironmentObject
来管理仪表板中的所有按钮,那就很容易了。让我们一步步实现该解决方案。
enum ButtonId {
case login
case signup
case forgotPassword
}
final class ButtonsManager: ObservableObject {
@Published var pressedButtonId: ButtonId?
}
ButtonStyle
。当按下/释放按钮时,该结构将告诉经理。为了让您检查按下/释放/启用/禁用按钮之间的差异,我使用了不同的颜色,但这只是一个示例,您可以根据需要自定义样式。struct ButtonsManagerStyle: ButtonStyle {
@Environment(\.isEnabled) private var isEnabled: Bool
@EnvironmentObject private var buttonsManager: ButtonsManager
let buttonId: ButtonId
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding()
.foregroundColor(.white)
.contentShape(Rectangle())
.background(isEnabled ? Color.red.opacity(configuration.isPressed ? 0.3 : 1) : Color.gray.opacity(0.8))
.onChange(of: configuration.isPressed) { isPressed in
if isPressed {
buttonsManager.pressedButtonId = buttonId
} else {
buttonsManager.pressedButtonId = nil
}
}
}
}
ViewModifier
以应用于您的按钮。为了不为仪表板中的所有按钮复制某些逻辑,这将很有用:struct ButtonsManagerModifier: ViewModifier {
@EnvironmentObject private var buttonsManager: ButtonsManager
let buttonId: ButtonId
func body(content: Content) -> some View {
content
.buttonStyle(ButtonsManagerStyle(buttonId: buttonId))
.disabled(buttonsManager.pressedButtonId != nil && buttonsManager.pressedButtonId! != buttonId)
}
}
// MARK: - Root View
struct MyRootView: View {
@StateObject private var buttonsManager = ButtonsManager()
var body: some View {
VStack(spacing: 50) {
Button {
print("Login did tap")
} label: {
Text("Login")
}
.modifier(ButtonsManagerModifier(buttonId: .login))
SignupNestedView()
ForgotPasswordNestedView()
}
.environmentObject(buttonsManager)
}
}
// MARK: - Signup
struct SignupNestedView: View {
var body: some View {
Button {
print("Signup did tap")
} label: {
Text("Sigup")
}
.modifier(ButtonsManagerModifier(buttonId: .signup))
}
}
// MARK: - Forgot Password
struct ForgotPasswordNestedView: View {
var body: some View {
ForgotPasswordNestedNestedView()
}
}
struct ForgotPasswordNestedNestedView: View {
var body: some View {
Button {
print("Forgot password did tap")
} label: {
Text("Forgot Password")
}
.modifier(ButtonsManagerModifier(buttonId: .forgotPassword))
}
}
您所要做的就是在根目录中注入环境对象(无论它是什么),并记住将我们为仪表板中的按钮创建的修改器设置为。结果如下: