📱

【Swift】触覚フィードバック(HapticFeedback)を使う

2022/07/21に公開

はじめに

触覚フィードバック (Haptic Feedback) を実装する機会があったのでその備忘録として本記事を書きました。

触覚フィードバックとは


Apple Developper Design / Playing haptics

ざっくり言うと iPhone でアプリを使用していて振動するアレのことです。
iOS アプリではUISwitch, UIPickerViewがデフォルトで触覚フィードバックが再生されます。

ベストプラクティス

一貫性を持って使用すること

Use haptics consistently. It’s important to build a clear, causal relationship between each haptic and the action that causes it so people learn to associate certain haptic patterns with certain experiences. If a haptic doesn’t reinforce a cause-and-effect relationship, it can be confusing and seem gratuitous. For example, if your app plays a specific haptic pattern when a game character fails to finish a mission, people associate that pattern with a negative outcome. If you use the same haptic pattern for a positive outcome like a level completion, people will be confused.
Apple Developper / Design / Pattern / Playing haptics

ある動作が成功した時のフィードバックと失敗した時のフィードバックの種類を同じにすると、ユーザーが混乱するので種類を分けましょう

触覚フィードバックのタイミングを合わせること

Use haptics in ways that complement other feedback in your app. When visual, auditory, and tactile feedback are in harmony — as they generally are in the physical world — the user experience is more coherent and can seem more natural. For example, match the intensity and sharpness of a haptic with the animation you use to accompany it. You can also synchronize sound with haptics; for developer guidance, see Delivering rich app experiences with haptics. Apple Developper / Design / Pattern / Playing haptics

View の表示、アニメーション、サウンドなどと触覚フィードバックを合わせて使用する場合、タイミングを合わせましょう

使用頻度に注意すること

Avoid overusing haptics. Sometimes a haptic can feel just right when it happens occasionally, but become tiresome when it plays frequently. It’s important to do user testing that can help you discover a balance that most people appreciate. Often, the best haptic experience is one that people may not be conscious of, but miss when it’s turned off.
Apple Developper / Design / Pattern / Playing haptics

ユーザーが疲れてしまうため、あまり頻繁にフィードバックを再生させるのは避けましょう

オプションとして使用すること

Make haptics optional. Let people turn off or mute haptics if they wish, and make sure people can still enjoy your app without them.
Apple Developper / Design / Pattern / Playing haptics

触覚フィードバックはさらなるオプションとして、まずは使用せずともユーザーが満足できるアプリを作成しましょう

物理的な影響を考慮すること

Be aware that playing haptics might impact other user experiences. By design, haptics produce enough physical force for people to feel the vibration. Ensure that haptic vibrations don’t disrupt user experiences involving the camera, gyroscope, or microphone.
Apple Developper / Design / Pattern / Playing haptics

カメラ、ジャイロスコープ、マイクを使用している場合に触覚フィードバックの振動が悪影響を及ぼさないか確認しましょう

触覚フィードバック(HapticFeedback)の使用方法

動作環境

  • Xcode 13.4.1
  • Swift 5.6.1
  • iOS 15.4.1
  • iPhone 13

Haptic Feedback の種類

1. UIImpactFeedback

var generator: UIImpactFeedbackGenerator?
    generator = UIImpactFeedbackGenerator(style: .light)
    generator?.prepare()
    generator?.impactOccurred()
    generator = nil

視覚体験を補完するための触覚フィードバック

UIImpactFeedbackの種類

  • Light
  • Medium
  • Heavy
  • Rigid
  • Soft

ここで UIImpactFeedback のサンプルを再生できます

2. UINotificationFeedback

var generator: UINotificationFeedbackGenerator?
    generator = UINotificationFeedbackGenerator()
    generator?.prepare()
    generator?.notificationOccurred(type: .success)
    generator = nil

タスクまたはアクションの結果に関する触覚フィードバック

UINotificationFeedback の種類

  • Success
    • タスクやアクションが成功したとき
  • Warning
    • タスクやアクションが警告を生成したとき
  • Error
    • タスクやアクションがエラーを起こしたとき

ここで UINotificationFeedback のサンプルを再生できます

3. UISelectionFeedback

使用例があまりピンと来なかったので今回は割愛します
よく使用されているケースなどがあれば教えてください 🙇

便利なサンプルコード

enum ImpactFeedbackStyle: Int {
    case light
    case medium
    case heavy
    case soft
    case rigid

    var value: UIImpactFeedbackGenerator.FeedbackStyle {
        return .init(rawValue: rawValue)!
    }

}

enum NotificationFeedbackType: Int {
    case success
    case failure
    case error

    var value: UINotificationFeedbackGenerator.FeedbackType {
        return .init(rawValue: rawValue)!
    }

}

enum Haptic {
    case impact(_ style: ImpactFeedbackStyle, intensity: CGFloat? = nil)
    case notification(_ type: NotificationFeedbackType)
}

final class HapticFeedbackManager {

    static let shared = HapticFeedbackManager()
    private init() {}
    private var impactFeedbackGenerator: UIImpactFeedbackGenerator?
    private var notificationFeedbackGenerator: UINotificationFeedbackGenerator?

    func play(_ haptic: Haptic) {
        switch haptic {
        case .impact(let style, let intensity):
            impactFeedbackGenerator = UIImpactFeedbackGenerator(style: style.value)
            impactFeedbackGenerator?.prepare()

            if let intensity = intensity {
                impactFeedbackGenerator?.impactOccurred(intensity: intensity)
            } else {
                impactFeedbackGenerator?.impactOccurred()
            }
            impactFeedbackGenerator = nil

        case .notification(let type):
            notificationFeedbackGenerator = UINotificationFeedbackGenerator()
            notificationFeedbackGenerator?.prepare()
            notificationFeedbackGenerator?.notificationOccurred(type.value)
            notificationFeedbackGenerator = nil
    }

}
HapticFeedbackManager.shared.play(.impact(.heavy))

impactOccurred(intensity: CGFloat)intensityには 0.0 ~ 1.0 までの値で振動の強度を調節することができるみたいです。ただ、実機で試したところ恐らくデフォルトが 1.0 なのでデフォルトよりも弱めたいときに使用するっぽいです 🤔

参考サイト

Apple Developper / Design / Pattern / Playing haptics
Documentation / UIKit / Animation and Haptics / UIFeedbackGenerator

Discussion