任何相当于 UIKit 的“触摸”的 SwiftUI 按钮,即当您的手指触摸时激活按钮?

Rog*_*ber 7 xcode ios13 swiftui

对于 SwiftUI,默认按钮行为相当于 UIKit 的“向上触摸”,当您的手指触摸按钮时激活,然后在按钮范围内抬起。

有什么方法可以将其更改为“触摸”,以便在您的手指触摸按钮时立即运行动作关闭?

ake*_*rra 12

虽然DragGesture在许多情况下效果很好,但它可能会产生一些不需要的副作用,例如在滚动视图中使用时,它将优先于滚动视图的内置手势处理。

在 SwiftUI 中,Buttons 已经跟踪按下的状态,因此此问题的解决方案是使用自定义ButtonStyle来允许挂钩状态的更改isPressed。

这是一个可行的解决方案:

定义一个自定义ButtonStyle:

struct CustomButtonStyle: ButtonStyle {
    
    var onPressed: () -> Void
    
    var onReleased: () -> Void
    
    // Wrapper for isPressed where we can run custom logic via didSet (or willSet)
    @State private var isPressedWrapper: Bool = false {
        didSet {
            // new value is pressed, old value is not pressed -> switching to pressed state
            if (isPressedWrapper && !oldValue) {
                onPressed()
            } 
            // new value is not pressed, old value is pressed -> switching to unpressed state
            else if (oldValue && !isPressedWrapper) {
                onReleased()
            }
        }
    }
    
    // return the label unaltered, but add a hook to watch changes in configuration.isPressed
    func makeBody(configuration: Self.Configuration) -> some View {
        return configuration.label
            .onChange(of: configuration.isPressed, perform: { newValue in isPressedWrapper = newValue })
    }
}
Run Code Online (Sandbox Code Playgroud)

您也可以didSet直接在修改器perform的块中编写逻辑onChange,但我认为这可以使其看起来干净。

将您的可点击视图包裹起来Button


struct ExampleView: View {

    @State private var text: String = "Unpressed"

    var body: some View {
        Text(self.text)
        Button(action: { ... }, label: {
            // your content here
        }).buttonStyle(CustomButtonStyle(onPressed: { 
            self.text = "Pressed!"
        }, onReleased: { 
            self.text = "Unpressed" 
        }))
    }
}

Run Code Online (Sandbox Code Playgroud)

然后你可以将任何你想要的逻辑传递给onPressed和onReleased参数CustomButtonStyle。

我使用它来允许自定义onPressed处理ScrollView.


kon*_*iki 10

您可以使用最小距离为零的 DragGesture 并为 DOWN (onChanged()) 或 UP (onEnded()) 定义一个闭包:

struct ContentView: View {
    @State private var idx = 0

    var body: some View {
        let g = DragGesture(minimumDistance: 0, coordinateSpace: .local).onChanged({
            print("DOWN: \($0)")
        }).onEnded({
            print("UP: \($0)")
        })

        return Rectangle().frame(width: 100, height: 50).gesture(g)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 遗憾的是,这与 List 或 ScrollView 中的滚动相冲突 (4认同)

Geo*_*e_E 8

_onButtonGesture您可以在 上使用隐藏方法View,该方法是公共的。它甚至不需要附加到Button,但它看起来更好,因为你看到了按下的效果。

代码:

struct ContentView: View {
    @State private var counter = 0
    @State private var pressing = false

    var body: some View {
        VStack(spacing: 30) {
            Text("Count: \(counter)")

            Button("Increment") {
                counter += 1
            }
            ._onButtonGesture { pressing in
                self.pressing = pressing
            } perform: {}

            Text("Pressing button: \(pressing ? "yes" : "no")")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

结果

由于帧速率的原因,GIF 看起来不太好,但每当您按下时pressing都会转到true,然后false松开。

  • 仅供参考,带有下划线前缀的属性意味着 Apple 不打算将其用于生产中。 (5认同)

sup*_*cio 5

您可以创建自定义视图修改器:

extension View {
    func onTouchDownGesture(callback: @escaping () -> Void) -> some View {
        modifier(OnTouchDownGestureModifier(callback: callback))
    }
}

private struct OnTouchDownGestureModifier: ViewModifier {
    @State private var tapped = false
    let callback: () -> Void

    func body(content: Content) -> some View {
        content
            .simultaneousGesture(DragGesture(minimumDistance: 0)
                .onChanged { _ in
                    if !self.tapped {
                        self.tapped = true
                        self.callback()
                    }
                }
                .onEnded { _ in
                    self.tapped = false
                })
    }
}

struct MyView: View {
    var body: some View {
        Text("Hello World")
            .onTouchDownGesture {
                print("View did tap!")
            }
    }
}
Run Code Online (Sandbox Code Playgroud)