How to create haptic feedback for a Button in SwiftUI?

前端 未结 4 1988
伪装坚强ぢ
伪装坚强ぢ 2021-02-12 22:15

I\'m trying to implement haptic feedback at the beginning of a tap for a Button in SwiftUI. Therefore I\'m trying to use simultaneousGesture, but I\'m sill struggling. I can\'t

相关标签:
4条回答
  • 2021-02-12 22:50

    I have a wrapper view that plays a haptic event, and then calls the action:

    struct HapticButton: View {
      let content: String
      let action: () -> Void
    
      init(_ content: String, _ action: @escaping () -> Void) {
        self.content = content
        self.action = action
      }
    
      var body: some View {
        
        Button(content) {
            HapticService.shared.play(event: .buttonTap)
            self.action()
        }
      }
    }
    

    Used like:

    HapticButton("Press me") { print("hello") } // plays haptic and prints
    
    0 讨论(0)
  • 2021-02-12 22:54

    pure SwiftUI solution below:

    HStack {
        Image("icon")
        Text("Login")
    }
    .onTouchGesture(
        touchBegan: { self.generateHapticFeedback = true },
        touchEnd: { _ in self.generateHapticFeedback = false }
    )
    

    Just add this snippet somewhere in your project:

    struct TouchGestureViewModifier: ViewModifier {
        let touchBegan: () -> Void
        let touchEnd: (Bool) -> Void
    
        @State private var hasBegun = false
        @State private var hasEnded = false
    
        private func isTooFar(_ translation: CGSize) -> Bool {
            let distance = sqrt(pow(translation.width, 2) + pow(translation.height, 2))
            return distance >= 20.0
        }
    
        func body(content: Content) -> some View {
            content.gesture(DragGesture(minimumDistance: 0)
                    .onChanged { event in
                        guard !self.hasEnded else { return }
    
                        if self.hasBegun == false {
                            self.hasBegun = true
                            self.touchBegan()
                        } else if self.isTooFar(event.translation) {
                            self.hasEnded = true
                            self.touchEnd(false)
                        }
                    }
                    .onEnded { event in
                        if !self.hasEnded {
                            let success = !self.isTooFar(event.translation)
                            self.touchEnd(success)
                        }
                        self.hasBegun = false
                        self.hasEnded = false
                    })
        }
    }
    
    extension View {
        func onTouchGesture(touchBegan: @escaping () -> Void = {},
                            touchEnd: @escaping (Bool) -> Void = { _ in }) -> some View {
            modifier(TouchGestureViewModifier(touchBegan: touchBegan, touchEnd: touchEnd))
        }
    }
    
    0 讨论(0)
  • 2021-02-12 22:55

    You can use UIFeedbackGenerator like this:

    let generator = UINotificationFeedbackGenerator()
    generator.notificationOccurred(.error)
    

    Or, as you're using SwiftUI, you'll be able to use CoreHaptics like this:

    let engine = try CHHapticEngine()
    try engine.start()
    
    let hapticEvent = CHHapticEvent(eventType: .hapticTransient, parameters: [
        CHHapticEventParameter(parameterID: .hapticSharpness, value: sharpness), CHHapticEventParameter(parameterID: .hapticIntensity, value: intensity),
    ], relativeTime: 0)
    let audioEvent = CHHapticEvent(eventType: .audioContinuous, parameters: [
        CHHapticEventParameter(parameterID: .audioVolume, value: volume),
        CHHapticEventParameter(parameterID: .decayTime, value: decay),
        CHHapticEventParameter(parameterID: .sustained, value: 0),
    ], relativeTime: 0)
    
    let pattern = try CHHapticPattern(events: [hapticEvent, audioEvent], parameters: [])
    let hapticPlayer = try engine.makePlayer(with: pattern)
    try hapticPlayer?.start(atTime: CHHapticTimeImmediate)
    
    0 讨论(0)
  • 2021-02-12 23:12

    As I know, this is the most simplest way to get haptic feedback in SwiftUI

    When tapping a button :

    Button(action: {
        let impactMed = UIImpactFeedbackGenerator(style: .medium)
        impactMed.impactOccurred()
    }) {
        Text("This is a Button")
    }
    

    You can change the intensity of the haptic feedback by replacing .medium with .soft, .light, .heavy, or .rigid

    or when tapping anything else :

    .onTapGesture {
     let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
                impactHeavy.impactOccurred()
    }
    

    If you want to make something like Haptic Touch, replace .onTapGesture with .onLongPressGesture like this

    .onLongPressGesture {
     let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
                impactHeavy.impactOccurred()
    }
    
    0 讨论(0)
提交回复
热议问题