HapticsManager
是一个 Swift 包,它提供了一个模块化且易于使用的接口,用于在你的应用程序中实现触觉反馈。它可以与 SwiftUI 无缝集成,使你能够通过可定制的触觉反馈来增强用户体验。
使用 Swift Package Manager 将 HapticsManager
添加到你的 Swift 项目中。
dependencies: [
.package(url: "https://github.com/markbattistella/HapticsManager", from: "1.0.0")
]
这个包的工作方式与 SwiftUI 的 .sensoryFeedback
API 类似,但通过允许你使用 UserDefaults
全局配置是否启用触觉反馈,从而增加了更多的灵活性。
使用 HapticsManager
,你可以轻松确定用户是否应该使用触觉反馈 —— 从而简化你的工作流程并保持熟悉的声明式语法。
主要优点是你可以集中控制 isHapticsEnabled
键,允许或有条件地启用触觉反馈,而无需在每次触发时重写逻辑。.sensoryFeedback
需要你在每次使用时都实现这个逻辑。
有三种使用 HapticsManager
的方法
静态操作格式允许你一致且简单地触发触觉反馈。在下面的示例中,每当 isSuccess
状态更改时,就会触发触觉反馈。
@State private var isSuccess: Bool = false
Button("isSuccess: \(isSuccess)") {
isSuccess.toggle()
}
.hapticFeedback(.notification(.warning), trigger: isSuccess)
你还可以使用条件来控制何时应触发触觉反馈,从而可以更集中地控制反馈的发生时间。
enum Phase { case inactive, active, completed }
@State private var phase: Phase = .inactive
Button("Update phase") {
switch phase {
case .inactive: phase = .active
case .active: phase = .completed
case .completed: phase = .inactive
}
}
.hapticFeedback(.impact(.medium), trigger: phase) { oldValue, newValue in
oldValue != .completed && newValue == .completed
}
enum Phase { case inactive, active, completed }
@State private var phase: Phase = .inactive
Button("Update phase") {
switch phase {
case .inactive: phase = .active
case .active: phase = .completed
case .completed: phase = .inactive
}
}
.hapticFeedback(.impact(.medium), trigger: phase) { newValue in
newValue == .completed
}
@State private var phase: Bool = false
Button("Toggle Phase") {
phase.toggle()
}
.hapticFeedback(.impact(.medium), trigger: phase) {
// Haptic feedback triggered
}
动态操作方法使你可以完全控制反馈类型以及触发反馈的条件。
enum LoadingState { case ready, success, failure }
@State private var loadingState: LoadingState = .ready
Button("Update loading state") {
switch loadingState {
case .ready: loadingState = .success
case .success: loadingState = .failure
case .failure: loadingState = .ready
}
}
.hapticFeedback(trigger: loadingState) { oldValue, newValue in
switch (oldValue, newValue) {
case (.failure, .ready):
return .notification(.warning)
case (.ready, .success):
return .notification(.success)
case (.success, .failure):
return .notification(.error)
default:
return nil
}
}
enum LoadingState { case ready, success, failure }
@State private var loadingState: LoadingState = .ready
Button("Update loading state") {
switch loadingState {
case .ready: loadingState = .success
case .success: loadingState = .failure
case .failure: loadingState = .ready
}
}
.hapticFeedback(trigger: loadingState) { newValue in
switch newValue {
case .success: return .notification(.success)
case .failure: return .notification(.error)
default: return nil
}
}
@State private var isLoading: Bool = false
Button("Toggle Loading") {
isLoading.toggle()
}
.hapticFeedback(trigger: isLoading) {
return .impact(.heavy)
}
HapticsManager
包含一个 .hapticEffectsEnabled
UserDefaults
键,允许你根据用户设置动态启用或禁用触觉反馈。
如果你想添加一个设置屏幕来切换触觉反馈,或者你需要一个总体逻辑来控制触觉反馈,例如,将其作为一项高级功能,这将很有帮助。
该包使用内部公开的 UserDefaults
套件来存储与触觉相关的设置
@main
struct MyAwesomeApp: App {
init() {
UserDefaults.haptic.register([
HapticUserDefaultsKey.hapticEffectsEnabled : true
])
}
var body: some Scene {
WindowGroup { ... }
}
}
或者手动更新它
Button("Turn haptics off") {
UserDefaults.haptics.set(false, for: HapticUserDefaultKeys.isHapticEnabled)
}
Button("Turn haptics on") {
UserDefaults.haptics.set(true, for: HapticUserDefaultKeys.isHapticEnabled)
}
重要
尽管你可以将 UserDefaults
注册到任何套件(.standard
或自定义),但该包只会响应内部 .haptic
套件,以防止应用程序不同部分之间发生意外冲突。
如果内置的反馈类型不够用,你可以使用 .custom(CustomHaptic)
Feedback
case 来创建自定义触觉模式。
要添加自定义触觉反馈类型
CustomHaptic
的枚举enum MyCustomHapticPattern: CustomHaptic {
case complexSuccess
func play() {
switch self {
case .complexSuccess:
playComplexSuccessHaptic()
}
}
}
play()
函数以定义你的自定义触觉反馈extension MyCustomHapticPattern {
// From HWS: https://www.hackingwithswift.com/books/ios-swiftui/adding-haptic-effects
func playComplexSuccessHaptic() {
var events = [CHHapticEvent]()
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)
}
do {
let pattern = try CHHapticPattern(events: events, parameters: [])
let engine = try CHHapticEngine()
try engine.start()
let player = try engine.makePlayer(with: pattern)
try player.start(atTime: 0)
} catch {
print("Failed to play pattern: \(error.localizedDescription).")
}
}
}
@State private var isSuccess: Bool = false
Button("isSuccess: \(isSuccess)") {
isSuccess.toggle()
}
.hapticFeedback(.custom(.complexSuccess), trigger: isSuccess)
欢迎任何形式的贡献! 请随时提交 pull request 或打开 issue,提出你的建议或改进意见。
HapticsManager
在 MIT 许可证下发布。 有关更多详细信息,请参见 LICENCE 文件。