【Swift】Rotation Gesture Recognizerの使い方。2つの指で部品を回転させる。(Swift 2.1、XCode 7.2)

2020年6月16日

Rotation Gesture Recognizerとは

本記事ではSwiftで使える部品のRotation Gesture Recognizer(以下、ローテーションリコグナイザー)について説明する。

Rotation Gesture Recognizer

 

ローテーションリコグナイザーとは、部品をタッチしている2つの指の座標を結ぶ直線が回転したことを検知する部品である。

前回記事のピンチリコグナイザーと使い方が似ているが、拡大縮小に比べると回転の使用頻度は多く無い。ということは、新しいアイディアがそこに埋まっているかも知れない。⇒「ピンチリコグナイザーとは

 

ローテーションリコグナイザーを使ってみる

実際にローテーションリコグナイザーを使ってみよう。

デバイス画面にラベルを配置する(下図赤矢印)。黄枠のアトリビュートインスペクタボタンを押して設定画面を表示する。Textに「テスト」、Colorを白、Backgroundに青、User Interaction Enabledにチェックを入れる

紫枠のアシスタントエディタボタンを押してViewController.swfitを開く。Ctrlキーを押しながらラベルをドラッグ&ドロップでソースコードまで運んで吹き出しの設定画面を表示させる(黄緑矢印)。

Connectionに「Outlet」、Nameに「testLabel」を入力しConnectボタンを押す。これでラベルをソースコードから操作できるようになった。

デバイス画面にラベルを追加する。

 

ローテーションリコグナイザーをラベルに配置する(下図赤矢印)。Ctrlキーを押しながら黄緑枠のローテーションリコグナイザーをソースコードまで運んで吹き出しの設定画面を表示させる(青矢印)。

Connectionに「Action」、Nameに「rotateLabel」、Typeに「UIRotationGestureRecognizer」を設定し、Connectボタンを押す。これで2つの指が回転したときのイベントをソースコードで受けれるようになった。

Rotation Gesture Recognizerをデバイス画面に配置

 

ViewController.swiftを以下のコードに変更する。ピンチリコグナイザーと同じように「回転時の呼び出しメソッド」が指を回すたびに呼び出される。

前回ドラッグ終了時の回転をクラス変数に保存し、ドラッグ中はこの回転を引き継いだアフィン変換を行っている。これにより、回転位置が元に戻ることなく回転を再開することができるということだ。

 

以下は実際のプレイ動画。ちなみにシミュレーターで2本の指を使うにはOptionキーを押しながら操作する。

拡大縮小と回転を同時に行う

ピンチリコグナイザーとローテーションリコグナイザーを使ってみて思うことといえば「拡大縮小と回転を同時に行いたい」である。同時に行うためのデリゲートが用意されているので使ってみよう。以降の手順は上記手順の続きである。

ピンチリコグナイザーをラベルに配置する(下図赤矢印)。黄緑枠のアシスタントエディタボタンを押してViewController.swiftを開く。Ctrlキーを押しながら紫枠のピンチリコグナイザーをドラッグ&ドロップでソースコードまで運んで吹き出しの設定画面を表示させる。

Connectionに「Action」、Nameに「pinchLabel」、Typeに「UIPinchGestureRecognizer」を入力してConnectボタンを押す。これで、ピンチイン、ピンチアウトのイベントをソースコードで受けれるようになった。

もう一度、Ctrlキーを押しながら紫枠のピンチリコグナイザーをドラッグ&ドロップでソースコードまで運んで吹き出しの設定画面を表示させる。Connectionに「Outlet」、Nameに「pinchRecognizer」を入力してConnectボタンを押す。

水色枠のローテーションリコグナイザーも同様にして吹き出しの設定画面を表示させ、Connectionに「Outlet」、Nameに「rotationRecognizer」を入力しConnectボタンを押す。これでピンチリコグナイザーとローテーションリコグナイザーをソースコードから操作できるようになった。

Pinch Gesture Recognizerをラベルに配置する

 

ViewController.swiftを以下のコードに変更する。

2つのリコグナイザーが同じタイミングで動いたときにデリゲートメソッドの「リコグナイザーの同時検知を許可するメソッド」が呼び出されるのでtrueを返して同時検知を許可している。

 

2つの指の拡大縮小操作が行われたときは「ピンチ時の呼び出しメソッド」が呼び出され、2つの指の回転操作が行われたときは「回転時の呼び出しメソッド」が呼び出される。

どちらのメソッドでも拡大縮小と回転の両方のアフィン変換を行う必要があるのが注意点である。そのため、「ドラッグ終了時のアフィン変換」「ドラッグ中のアフィン変換」をクラス変数に持たせている。

ややこしくなってきたので、「ドラッグ終了時のアフィン変換」が必要な理由について回転の具体例を用いて説明する。

部品がどれだけ回転したかは、「回転時の呼び出しメソッド」の引数から知ることができ、その角度は基準点からの角度になる。

例えば、指を瞬時に11度回転させて1回目のメソッド呼び出しで回転角度11度が通知されたとする。そのまま指を画面から離さずに10度回転させて2回目のメソッド呼び出しが行われたときは21度(=11度+10度)が通知される。さらに指を12度回転させて3回目のメソッド呼び出しでは33度(=11度+10度+12度)が通知される。

つまり、ドラッグ中のメソッド呼び出しは前回メソッド呼び出し時からの回転角度が通知されるのではなく、部品の初期状態からの回転角度が通知される。ということだ。

rotation_recognizer_exam1

 

そのため、一度画面から指を離したあとに再回転をさせるときは前回の回転を含めてアフィン変換をする必要がある。しかし、ドラッグ中の回転も含めて前回呼び出し時の回転角を引き継がせると、下図のように回転角が被って通常より大きな回転になってしまう。

前回の回転角度を含めてアフィン変換をした場合

 

そのため、「ドラッグ終了時のアフィン変換」をクラス変数に保存しておき、引き継がせる回転角度を固定させるわけである。

一方、「回転時の呼び出しメソッド」の中で行う拡大縮小のアフィン変換は、ドラッグ中に変化している部品のサイズを反映するために直近の拡大縮小のアフィン変換が必要である。そのため、「ドラッグ中のアフィン変換」をクラス変数に保存し、他のメソッドで利用でるようにしている。

以下は実際のプレイ動画

 

回転させる部品の中の部品も一緒に回転し、機能してくれるのが嬉しい。