iPhone 7 から以下のクラスを使うことでプログラム側から Taptic Engine を操作できるようになりました。早速実機で動作を確認してみました。
API の種類
クラスとしては以下の4つです。UIFeedbackGenerator
は抽象クラスとして用意されているので実質2つのクラスを利用する感じかと思います。
- UINotificationFeedbackGenerator
- 既定の動作シーケンスを表す enum UINotificationFeedbackType を指定して動かせる
- success
- warning
- error
- 既定の動作シーケンスを表す enum UINotificationFeedbackType を指定して動かせる
- UIImpactFeedbackGenerator
- 単発の振動の強さを表す enum UIImpactFeedbackStyle を指定して動かせる
- light
- medium
- heavy
- 単発の振動の強さを表す enum UIImpactFeedbackStyle を指定して動かせる
- UISelectionFeedbackGenerator
- UIImpactFeedbackGenerator の light よりも弱いフィードバック
- 選択が変更されたときに使うことを想定されている
- UIDatePicker はデフォルトでこれが使われているようです。
- UIFeedbackGenerator
- 上記3つのクラスのベースクラスで抽象クラス
実装
UINotificationFeedbackGenerator を使う
既定シーケンスを実行できる UINotificationFeedbackGenerator であれば以下のコードだけで動かせます。
let generator = UINotificationFeedbackGenerator()
generator.prepare()
generator.notificationOccurred(.error)
UINotificationFeedbackGenerator
を生成したあと、そのインスタンスに対して notificationOccurred メソッドを呼び出し、その引数でどのような通知振動を起こすかを指定します。notificationOccurred を呼び出す前に prepare を呼んでおきます。フィードバックが発生する待機時間を最小限に抑えることができるようですが、prepare() を呼ばなくても体感としてはかわりませんでした。
振動の違いは以下の通りです。
- .error
- トゥトゥトゥ という感じで3回振動
- .warning
- トントン と2回振動
- .success
- トントン と2回振動
.warning
と .success
の違いがほとんど感じられませんでした。耳を当ててみると .warning
は『カンカン』と甲高い感じの2回振動に感じます。.success
は『グ カン』という感じで1発目の振動が重い感じです。この感じ方は人によって差が出そうですが些細な違いでしょう。
UIImpactFeedbackGenerator を使う
こちらのクラスは振動の強弱だけの指定で振動は組み合わせでなく単発です。
let generator = UIImpactFeedbackGenerator(style: .medium)
generator.prepare()
generator.impactOccurred()
UINotificationFeedbackGenerator と同様に enum で区別はするのですが、こちらは generator の生成時に style を指定して、impactOccurred()
で振動をさせる感じです。
振動の違いは書くほどでもなく名称通りの強弱がついた振動になっています。個人的には .light
になると振動したのに気付かないくらいです。.heavy
でもそこまで強い振動には感じませんでした。
UISelectionFeedbackGenerator を使う
使い方は1番簡単です。UISelectionFeedbackGenerator
のインスタンスを作って、selectionChanged()
を呼ぶだけです。
let generator = UISelectionFeedbackGenerator()
generator.prepare()
generator.selectionChanged()
ソースコードコメントには「選択が変わったときに使う」という趣旨のことが書かれていますがわざわざテーブルビューやその他の "選択状態" がある UI じゃなくても呼び出すだけなら可能です。おそらくはお作法としてこう使って欲しいという意図なのかと思います。
UIImpactFeedbackGenerator を複合的に実行してみる
結論から言うとうまくいかないです。
まず、GCD を使って Background Thread でタイミングをずらしつつ実行しようと思うと以下のようなエラーが出てきました。
[Feedback] trying to activate the feedback engine from a non-main thread, this is unsupported.
現状は Main Thread でしか実行できないようです。
GCD で DispatchQueue.main.async
で少しずらしつつ実行すると、感触として1回しか振動していないように感じます。DispatchQueue.main.asyncAfter
でほんの少しずらすと2回振動させることは出来ました。ただしこれで UINotificationFeedbackGenerator
のような複数の振動を組み合わせたものを自作するのは現実的ではないでしょう。
考察
UINotificationFeedbackGenerator
は何らかのタスク実行のフィードバックとして使う感じでしょうか。
- Web API との通信失敗時にアラートなどの UI を表示させると同時に
.error
を使う - フォームの入力時に不正文字種が入力された時に
.warning
を使う
などが浮かびます。
UIImpactFeedbackGenerator
は単発なので
- ボタンタップ時に
.medium
や.light
で演出- 特に指でボタンが隠れて見た目上のフィードバックが返せないような小さいボタンに有効かも
- 設定.app の UISwitch の操作時に Apple はこれを使っているようです
-
(実現できるか未検証ですが)複数の振動を組み合わせて独自のシーケンスを作ってみる- 現実的ではなかった
というような利用が考えられるのではないでしょうか。
UISelectionFeedbackGenerator
はヘッダーコメントに書かれているように選択状態が変わったときに使うことが推奨されてそうです。UIDatePicker の動きを参考にしてみると良いと思います。
サンプルコード
これらの動作を検証したサンプルコードを github に置いてあるので興味のある方はどうぞ。