在SwiftUI中检测按钮外的触摸

3

我有一个重置按钮,需要先确认。如果用户触摸组件外部,我想将 isSure 设为 false。

我能否从按钮组件中实现这个功能?

这是我的按钮:

struct ResetButton: View {
    var onConfirmPress: () -> Void;
    @State private var isSure: Bool = false;

    var body: some View {
        Button(action: {
            if (self.isSure) {
                self.onConfirmPress();
                self.isSure.toggle();
            } else {
                self.isSure.toggle();
            }
        }) {
            Text(self.isSure ? "Are you sure?" : "Reset")
        }
    }
}
2个回答

13

以下是其中一种实现方式:

struct ContentView: View {

var onConfirmPress: () -> Void

@State private var isSure: Bool = false

var body: some View {
    GeometryReader { geometry in
        ZStack {
            // a transparent rectangle under everything
            Rectangle()
                .frame(width: geometry.size.width, height: geometry.size.height)
                .opacity(0.001)   // <--- important
                .layoutPriority(-1)
                .onTapGesture {
                    self.isSure = false
                    print("---> onTapGesture self.isSure : \(self.isSure)")
            }
            Button(action: {
                if (self.isSure) {
                    self.onConfirmPress()
                }
                self.isSure.toggle()
            }) {
                Text(self.isSure ? "Are you sure?" : "Reset").padding(10).border(Color.black)
            }
        }
    }
}
}

6
基本上,我们有一些视图,并且希望在其背景上轻击时执行某些操作 - 这意味着我们想要添加一个巨大的背景来注册轻击。请注意,.background 仅提供主视图的大小,但始终可以设置明确不同的大小!如果您知道自己的大小,那很好,否则 UIScreen 可能会起作用...
这种方法可能有点hacky,但似乎有效!
extension View {
    @ViewBuilder
    private func onTapBackgroundContent(enabled: Bool, _ action: @escaping () -> Void) -> some View {
        if enabled {
            Color.clear
                .frame(width: UIScreen.main.bounds.width * 2, height: UIScreen.main.bounds.height * 2)
                .contentShape(Rectangle())
                .onTapGesture(perform: action)
        }
    }

    func onTapBackground(enabled: Bool, _ action: @escaping () -> Void) -> some View {
        background(
            onTapBackgroundContent(enabled: enabled, action)
        )
    }
}

使用方法:

SomeView()
  .onTapBackground(enabled: isShowingAlert) {
    isShowingAlert = false
  }

这可以很容易地改成采用绑定:

func onTapBackground(set value: Binding<Bool>) -> some View {
    background(
        onTapBackgroundContent(enabled: value.wrappedValue) { value.wrappedValue = false }
    )
}

// later...
SomeView()
    .onTapBackground(set: $isShowingAlert)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接