[SwiftUI 100 天] Flashzilla - 振动反馈

1,969 阅读4分钟

译自 www.hackingwithswift.com/books/ios-s…

更多内容,欢迎关注公众号 「Swift花园」

喜欢文章?不如来个 🔺💛➕三连?关注专栏,关注我 🚀🚀🚀

用 UINotificationFeedbackGenerator 和 Core Haptics 来产生振动

尽管 SwiftUI 并不内建震动反馈的功能,我们可以借助 UIKit 和 Core Haptics 轻松地实现震动功能。这两个框架都是内建于系统的,对于所有 iPhone 平台都是可用的。以防你不了解震动反馈这个术语,我简单解释一下,“震动反馈” 在设备中内置了一个小的马达,用于提供点击和振铃的感知。

UIKit 有一个非常简单的震动反馈实现,这并不意味着你就可以忽略它。这个功能本来就可以用最简单的方式使用,比如只需要反馈内置的 “成功” 或者 “失败”。这意味着,用户可以通过学习,掌握某件事情的感知是什么样的。比如,你使用了成功的震动,那么某些用户 —— 尤其是那些重度依赖震动反馈的用户,比如盲人,可以不借助应用的其他输出信息就知道某个操作的结果。

为了尝试 UIKit 的震动反馈,添加下面这个方法到 ContentView

func simpleSuccess() {
    let generator = UINotificationFeedbackGenerator()
    generator.notificationOccurred(.success)
}

你可以在某个手势,比如 onTapGesture() 中触发这个反馈:

Text("Hello, World!")
    .onTapGesture(perform: simpleSuccess)

试着把 .success 替换成 .error 后者 .warning,看看其间的差别 —— 我认为 .success.warning 相似但是不同。

对于更高级的震动反馈,Apple 提供了一个叫 Core Haptics 的框架。看起来 Apple 的团队为其倾注了不少心血,我认为这个框架是隐藏在 iOS 背后的明珠 —— 我在它刚刚发布的时候就被深深地吸引了!

Core Haptics 能让我们通过组合点击,跟进的振铃,参数曲线等来定制大量的自定义震动反馈。我不会逐一深入,因为这样就脱离主题了,不过我会给一个例子,让你自行尝试。

首先,导入这个框架:

import CoreHaptics

然后,创建一个 CHHapticEngine 实例作为属性 —— 它是实际负责创建震动的对象。

@State private var engine: CHHapticEngine?

在我们的主视图出现时,我们就需要准备好震动。我们可以通过添加 handler 来帮助应用的活动回归活跃,比如当应用进入后台的时候。简单起见,如果设备支持震动反馈,我们才执行反馈,并且在出错时打印错误信息。

把下面这个方法添加到 ContentView

func prepareHaptics() {
    guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return }

    do {
        self.engine = try CHHapticEngine()
        try engine?.start()
    } catch {
        print("创建引擎时出现错误: \(error.localizedDescription)")
    }
}

再接下来是有趣的部分:我们可以通过配置参数来控制震动的强度(.hapticIntensity) 以及“锐度” (.hapticSharpness),然后放入一个震动事件,并且设置相对时间偏移。“锐度”听起来是一个很奇怪的术语,不过只要你尝试之后,就会发现这个词说得通了。0 的锐度和 1 的锐度感觉是完全不同的。至于相对时间偏移,能让我们在单个序列里创建许多震动。

把下面这个方法添加到 ContentView

func complexSuccess() {
    // 确保设备支持震动反馈
    guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return }
    var events = [CHHapticEvent]()

    // 创建一个强烈的,锐利的震动
    let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: 1)
    let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: 1)
    let event = CHHapticEvent(eventType: .hapticTransient, parameters: [intensity, sharpness], relativeTime: 0)
    events.append(event)

    // 将震动事件转换成模式,立即播放
    do {
        let pattern = try CHHapticPattern(events: events, parameters: [])
        let player = try engine?.makePlayer(with: pattern)
        try player?.start(atTime: 0)
    } catch {
        print("Failed to play pattern: \(error.localizedDescription).")
    }
}

为了尝试我们的自定义震动,把 ContentViewbody 属性修改成下面这样:

Text("Hello, World!")
    .onAppear(perform: prepareHaptics)
    .onTapGesture(perform: complexSuccess)

你可以修改强度,锐度和事件,尝试不同参数下的震动效果。代码如下:

for i in stride(from: 0, to: 1, by: 0.1) {
    let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: Float(i))
    let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: Float(i))
    let event = CHHapticEvent(eventType: .hapticTransient, parameters: [intensity, sharpness], relativeTime: i)
    events.append(event)
}

for i in stride(from: 0, to: 1, by: 0.1) {
    let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: Float(1 - i))
    let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: Float(1 - i))
    let event = CHHapticEvent(eventType: .hapticTransient, parameters: [intensity, sharpness], relativeTime: 1 + i)
    events.append(event)
}

我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~

Swift花园微信公众号