【Swift】端末をバイブさせる

2022.05.08

ユーザーがあるアクションを実行した時に端末をバイブさせて触覚的に知らせたかったので調べてみました。

環境

  • Xcode 13.3
  • iPhone 12mini
  • iOS 15.4.1

デバイスを振動させるには、UIFeedbackGenerator のサブクラスを使用し触覚フィードバック振動させる方法とAudioToolboxを使用した振動方法があります。

UIFeedbackGenerator

UIFeedbackGeneratorのサブクラスには、以下の三つがあります。

  • UIImpactFeedbackGenerator
  • UISelectionFeedbackGenerator
  • UINotificationFeedbackGenerator

UIImpactFeedbackGenerator

物理的な影響をシミュレートする触覚を作成するジェネレータです。アプリ上で衝撃を表現するのに活用出来ます。

使用方法は簡単でフィードバックジェネレータのインスタンス生成をして、impactOccurred()を呼ぶと衝撃の触覚を感じれます。

let feedbackGenerator = UIImpactFeedbackGenerator(style: .heavy)
feedbackGenerator.impactOccurred()

UIImpactFeedbackGeneratorの初期化時に、UIImpactFeedbackGenerator.FeedbackStyleを引数で渡してスタイルを決定します。

UIImpactFeedbackGenerator.FeedbackStyle

  • case heavy
    • 大きくて重たいユーザーインターフェイス要素の衝突
  • case light
    • 小さくて軽いユーザーインターフェイス要素の衝突
  • case medium
    • 普通サイズのユーザーインターフェイス要素の衝突
  • case rigid
    • iOS 13から追加されているものでドキュメントの内容は空だが、名前から推測するには堅い衝突のフィードバックに適していそう
  • case soft
    • iOS 13から追加されているものでドキュメントの内容は空だが、名前から推測するにはソフトな衝突のフィードバックに適していそう

impactOccurred

インパクトが発生したことをジェネレータに通知し、ジェネレータはスタイルの値に基づいて適切な触覚を再生します。impactOccurredではなく、impactOccurred(intensity:)を使用すれば衝撃の強度も調節することが出来ます。

使ってみた感想

動画や文章では振動具合が上手にお伝えできませんが、インパクトという名前から想像していたものとは違ってFeedbackStyleを.heavyにした場合で振動を発生させた場合でも個人的にはあまり強くない、伝わりにくいなと感じました。

UISelectionFeedbackGenerator

選択の変更を示す触覚を作成するジェネレータです。

特にFeedbackStyleや強度の調整も無い為、使い方はシンプルです。

let feedbackGenerator = UISelectionFeedbackGenerator()
feedbackGenerator.selectionChanged()

使ってみた感想

本当に一瞬、「コツ」という触覚を伝えてくれます。

UINotificationFeedbackGenerator

成功、失敗、および警告を伝達するための触覚を作成するジェネレータです。ユーザーがあるアクションを実行した時に端末をバイブさせて触覚的に知らせたいという今回やりたい事と一番合っていそうです。

フィードバックジェネレータのインスタンス生成して、notificationOccurred(_:)の引数にUINotificationFeedbackGenerator.FeedbackTypeを渡してフィードバックを発生させます。

let feedbackGenerator = UINotificationFeedbackGenerator()
feedbackGenerator.notificationOccurred(.success)

UINotificationFeedbackGenerator.FeedbackType

FeedbackTypeには失敗、成功、警告を表す3タイプがあります。

  • case error
    • タスクが失敗したことを示す通知フィードバックタイプ。
  • case success
    • タスクが正常に完了したことを示す通知フィードバックタイプ。
  • case warning
    • タスクが警告を生成したことを示す通知フィードバックタイプ。

使ってみた感想

自分の感覚が鈍いせいか、.error.successの違いがあまり分からなかった。.warningはその二つよりもやや振動が少ない印象

UIFeedbackGeneratorは設定に左右される

紹介したUIFeedbackGeneratorのサブクラスですが、設定 > サウンドと触覚 > システムの触覚 をオフにすると振動が発生しなくなります。必ず振動させてユーザーに伝えたいという時には使わない方が良さそうです。

prepare(オプション)

今回は、prepare()を使用していませんが、UIFeedbackGeneratorのインスタンス生成後に、prepare()を使用することがドキュメントで推奨されていました。

prepare()メソッドの使用は任意ですが、強く使用を推奨します。このメソッドを呼び出すとフィードバックのレイテンシーが可能な限り低ります。

下記のようにprepare()を呼び出してすぐにフィードバックを発生するような場合では、遅延は改善されないようです。

let feedbackGenerator = UINotificationFeedbackGenerator()
feedbackGenerator.prepare()
feedbackGenerator.notificationOccurred(.warning)

UIFeedbackGeneratorの解放(オプション)

準備されたジェネレーターが不要になった場合は、ジェネレーターオブジェクトへのすべての参照を削除し、システムに割り当てを解除させます。これにより、TapticEngineはアイドル状態に戻ります。

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

インスタンス変数にnilを代入すると、古いジェネレーターへの参照が削除されます。

TapticEngine

Tapticエンジンはバイブレーターに代わって採用された振動装置で、通常のバイブレータのモーターによる回転と異なり、磁石でウエイトを左右に動かすことで、「コツコツ」という振動を発生させている。

UIFeedbackGeneratorによるフィードバック振動はバイブレータによる振動とは異なる種類の振動で明らかな振動を伝える用途には向いてなさそうですね。

AudioToolBoxを使って分かりやすく振動させる

UIFeedbackGeneratorによるフィードバック振動ではなく、明らかなバイブレーションをさせるならAudioServicesPlaySystemSound(kSystemSoundID_Vibrate)を使用します。

AudioToolBoxをインポートし、

import AudioToolbox

バイブを行いたい箇所で、AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)を呼び出すだけです。

// 例
@IBAction private func vibrateDevice() {
    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
}

この方法だと、設定でシステムの触覚をオフにしても振動させることが出来ます。ただし、ドキュメントに記載してありますが、iPod Touchでは振動しないようです。

SystemSoundID

SystemSoundIDで選択出来るバイブレーションの種類は他にもあります。AudioServices(非公式)でカテゴリがVibrateとなっているIDをAudioServicesPlaySystemSound(_:)の引数で入力してみてお気に入りの振動を見つけてみてください。

公式のSystemSoundIDのリストを見つけれなかったのですが、こちらの記事を見てみると上記リスト以外のIDで利用出来るものが他にもあるようです。

おわりに

触覚フィードバック振動を使う方法と、バイブレータによる振動を使用する方法を学びました。それぞれに決まった用途があるのでそれに合わせて使っていきたいと思います。

参考