如何在SwiftUI中为按钮创建触觉反馈?

时间:2019-06-25 07:06:14

标签: ios

我正在尝试在SwiftUI中为Button轻按开始时实现触觉反馈。因此,我正在尝试同时使用手势,但是我仍在挣扎。我无法弄清楚水龙头何时开始。

还没有为Swift UI实现触觉反馈,所以我想我可以从UIKit中将其融合进来?

我试图实现TapGesture的更新方法,但它似乎无能为力。这就是到目前为止。感谢您的提示。

<?php

function multi_key_in_array($needle, $haystack, $key) 
{
    foreach ($haystack as $h) 
    {
        if (array_key_exists($key, $h) && $h[$key]==$needle) 
        {
            return true;
        }
    }
    return false;
}


$myArray = Array
(
    'Standardbox' => Array
        (
            'details' => Array
                (
                    'name' => 'Standardbox'
                ),

            'resources' => Array
                (
                    0 => Array
                        (
                            'resourceId' => 1,
                            'resourceName' => 'Knife',
                            'amount' => 1,
                            'unit' => 2
                        ),

                    1 => Array
                        (
                            'resourceId' => 2,
                            'resourceName' => 'Fork',
                            'amount' => 1,
                            'unit' => 2
                        )

                )

        )

);


if(multi_key_in_array(1, $myArray['Standardbox']['resources'], "resourceId"))
{
     echo 'true';
} else {
    echo 'false';
}

> Blockquote

5 个答案:

答案 0 :(得分:14)

据我所知,这是在SwiftUI中获得触觉反馈的最简单方法

点击按钮时:

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

您可以通过将.medium替换为.light.heavy来降低或增加触觉反馈的强度

或在点击其他任何内容时:

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

如果您想制作类似Haptic Touch的东西,请像这样用.onTapGesture替换.onLongPressGesture

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

答案 1 :(得分:1)

您还可以将 Haptic 生成器封装在单例中:

import UIKit

class Haptics {
    static let shared = Haptics()
    
    private init() { }

    func play(_ feedbackStyle: UIImpactFeedbackGenerator.FeedbackStyle) {
        UIImpactFeedbackGenerator(style: feedbackStyle).impactOccurred()
    }
    
    func notify(_ feedbackType: UINotificationFeedbackGenerator.FeedbackType) {
        UINotificationFeedbackGenerator().notificationOccurred(feedbackType)
    }
}

呼叫站点:

// As a button action
Button(action: {
    // some action
    Haptics.shared.play(.heavy)
}, label: {
    Text("Button")
})

// As a tap gesture on a View
SomeView()
.onTapGesture(perform: {
    Haptics.shared.play(.light)
})

// In a function
func someFunc() {
    Haptics.shared.notify(.success)
}

选项:

Haptics.shared.play(.heavy)
Haptics.shared.play(.light)
Haptics.shared.play(.medium)
Haptics.shared.play(.rigid)
Haptics.shared.play(.soft)
                
Haptics.shared.notify(.error)
Haptics.shared.notify(.success)
Haptics.shared.notify(.warning)

答案 2 :(得分:0)

您可以像这样使用UIFeedbackGenerator

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

或者,当您使用SwiftUI时,您将可以像这样使用CoreHaptics

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)

答案 3 :(得分:0)

下面的纯SwiftUI解决方案:

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

只需将此代码段添加到项目中的某个位置即可:

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))
    }
}

答案 4 :(得分:0)

我有一个包装视图,该视图播放一个触觉事件,然后调用该动作:

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()
    }
  }
}

使用方式:

HapticButton("Press me") { print("hello") } // plays haptic and prints