忙しい人のためのCore Haptics

#はじめに

iOS10からUIKitにはUIFeedbackGeneratorというAPIが追加されており、簡単にHapticFeedbackを実装することができました。

iOS13が公開され、UIFeedbackGeneratorに比べてカスタマイズできるHaptic Feedbackを作成できるようになったのですが、UIFeedbackGeneratorがあるUIKitにではなく、新しくCore HapticsというFrameworkが追加されました。

この記事はCore Hapticsとはどういう物なのか、実装方法などを簡単にまとめてみました。

###HapticFeedbackとは

UISwitchでON/OFFを切り替えたり、UISliderでSliderを端までスワイプしたり、UIDatePickerでスクロールした時などの特定のアクションを行うと起きる振動のことで、たくさんの場所に組み込まれており、いくつかの種類が存在します


#Core Hapticsとは
 
### 対応機種

iPhone8以降の全機種で使用することができます。

### UIFeedBackGeneratorとCore Haptics

UIFeedBackGeneratorはNotification,Impact,Selectionなど、アクションを起こしたユーザーに対してFeedBackを行うことにより、UXを向上させることが目的とされています。

対して、Core Hapticsは自分でHapticFeedBackを内容、使うタイミングなどを自由に設定したい場合に使用します。
他のAPI(Core Animation, AVAudioEngine)との連動も可能なことや、Core  HapticsはAudioAPIであり、今までAppleが実装していた音と連動して使用することなど(例:UIDatePickerのスクロール)も可能なので、UIFeedBackGeneratorに比べて豊かな表現を行うことができます。

WWDCでは特に活用できるジャンルとして、ゲーム、ARなどが挙げられていました・

<img width="816" alt="スクリーンショット 2019-12-14 17.03.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300780/b83a0c00-89f8-30f6-98ad-6eda5aac26be.png"><img width="816" alt="スクリーンショット 2019-12-14 17.03.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300780/a5356d9f-d894-3ea5-a1bc-4c56bf8f5892.png">


#コード
それでは実際に実装しながら見ていきたいと思います。

## モジュールのインポート

```swift

import CoreHaptics
```

##HapticEngine作成

```swift

var hapticEngine: CHHapticEngine?

do {
    hapticEngine = try CHHapticEngine()
    try hapticEngine?.start()
} catch {
    print("Error \(error)")
}
```
・CHHapticEngineには`capabilitiesForHardware`というメソッドが存在しており、HapticEngineを作成する前にデバイスが実行されているデバイス環境でHapticsFeedBackがサポートされているか確認することもできます。

```swift
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return }
```

・そのほかにも`stoppedHandler `,`resetHandler `が用意されており、アプリケーション以外の動作でエンジンが終了される時などに使用できるコールバックも用意されています。

```swift
var stoppedHandler: CHHapticEngine.StoppedHandler { get set }

var resetHandler: CHHapticEngine.ResetHandler { get set }
```

## HapticEventParameterを元にHapticEventを作成
再生するコンテンツを作成します

```swift
	
//EventParameterを作成
let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: 1)
let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: 1)

//EventParameter,EventType,Time,からEventを作成します。
let event = CHHapticEvent(eventType: .hapticTransient, parameters: [intensity, sharpness], relativeTime: 0)
```

#### EventParameterを作成
・Eventで使われるParameterを作成します、ParameterTypeとしては音の強さ、明瞭さなど複数の種類が存在します。

#### EventParameter,EventType,Time,からEventを作成します。
・先ほど作成したEventParameter,EventType,Time,からEventを作成、eventTypeとしては単発で短い動き、継続的、音とHapticFeedBackを連動させるなどがあります。

## 再生

```swift
		
do {
    //先ほど作ったEventからPatternを作成
    let hapticPattern = try CHHapticPattern(events: [event], parameters: [])
    //PatternのPlayerを作成
    let hapticPlayer = try hapticEngine?.makePlayer(with: hapticPattern)
    try hapticPlayer?.start(atTime: CHHapticTimeImmediate)
} catch let error{
    print("Error: \(error)")
}
```

・イベントを１つのPatternとしてラップして、そのPatternに対するPlayerを作成します。


これがCoreHapticsの基本的なコードになります


## Dynamic Parameter

UIFeedBackGeneratorとの違いの１つとして、Event Parameterの値を増減することや複数の動きを組み合わせる事が可能です。

・上記のCHHapticEventは単純な振動のみですが、下記のようにするとrelativeTimeを元にタイムラインを設定することにより、複数イベントを作成して、パターンとして扱うこともできます。

```swift
//単発のEvent
let short1 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 0)
let short2 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 0.2)
let short3 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 0.4)
let short4 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 0.6)
let short5 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 0.8)
let short6 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 1.0)

//継続的なEvent
let long1 = CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 1.2, duration: 0.5)
let long2 = CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 1.8, duration: 0.5)
let long3 = CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 2.4, duration: 0.5)

```


#最後に

今回紹介したのはCore Hapticsの簡単な部分にすぎません、他のPatternの作成方法として、APHP(Apple Haptic Audio Pattern)と呼ばれるファイルを用いてコードからHapticPatternを分離させる方法や、CHHapticParameterCurveといった再生中に値を増減させるなどより自由度の高い作成方法もありますので、気になった方はWWDCの動画やDocumentなどをご覧になってみてください。

ありがとうございました。

#参考リンク

[Haptics - Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/ios/user-interaction/haptics/)

[Core Haptics](https://developer.apple.com/documentation/corehaptics)

[Introducing Core Haptics](https://developer.apple.com/videos/play/wwdc2019/520/)