以前、Androidのジェスチャーの処理を記事にした。

[Android] 様々なジェスチャーを処理する(1) 拡大縮小
[Android] 様々なジェスチャーを処理する(2) 移動
[Android] 様々なジェスチャーを処理する(3) 回転 

今回はiOSのジェスチャーの処理を実装していく。

まず、先にジェスチャーを処理するメソッドを全て用意してしまおう。

次にSoryboardの準備だ。
ImageViewを一つだけ置いて、これに対してジェスチャーを追加していく。
ios_gesture_ss1

タップ
まずStoryboardでTapGestureRecognizerを先ほどのImageViewにドラッグする。
ios_gesture_ss2
すると、DocumentOutlineにTapGestureRecognizerが表示されるので、それを選択する。
ios_gesture_ss3
その状態でConnections Inspectorを見るとこのようになっているはずだ。
ios_gesture_ss4
この中のSent Actionsにあるselectorの右側の丸ボタンからViewControllerへ矢印を引っ張ろう。
ios_gesture_ss5
すると、このように先ほど定義したhandleTapメソッドが出てくるので選択する。
これで、接続は完了だ。
ios_gesture_ss6
あとはhandleTapを実装すればいいだけだ。
今回はデバッグ出力を行うだけの簡単なものにしておこう。

さあ、実行だ!
…おかしい、デバッグ出力が表示されない。

実はまだやり残したことがあった。
ImageViewのAttributes InspectorにあるUser Interaction Enabledにチェックを入れる必要があるのだ。
ios_gesture_ss7
もう一度実行してみよう。
今度はちゃんとデバッグ出力が表示された!

ローテーション
次は回転を実装する。
RotationGestureRecognizerをImageViewに追加して、handleRotationに接続するまでの手順はタップと同じだ。
実装内容を見ていこう。

1.GestureRecognizerの対象となるViewのtransformを変更する。
 角度は相対的な値として計算している。

2.角度を常に相対的にするために、このようにリセットを行う。

さあ、実行してみよう。
回転したはずだ!

…回転はした。
しかし、奇妙な動きをしていることに気付いたはずだ。
おかしな点を軸にして回転している。
私達が求める仕様はImageViewの中心を軸にして回転してほしいというものだ。

調べてみると、ここに答えがあった。
iphone - Issue while using UIRotationGestureRecognizer to rotate Image? - Stack Overflow
どうやらAutoLayoutがオンになっているのがいけないらしい。
さっそくオフにしてみた。
ios_gesture_ss8
もう一度実行してみよう。
今度は想定通りの動きになった!

ピンチ
次はピンチによる拡大縮小を実装する。
基本的な手順はローテーションと同じだ。
イベント処理を以下のように実装しよう。

ここもローテーションと同じようなものなので特に説明はいらないだろう。

実行してみよう。
ピンチイン・ピンチアウトで拡大縮小出来るようになった!

パン
次はパンを実装する。
要は移動処理のことだ。
基本的な手順はローテーションと同じだ。
イベント処理を以下のように実装しよう。

1.親のView上での移動量を取得する。
 translationInViewに渡すのはrecognizer.viewではなくself.viewなので、間違えないようにしたい。

2.対象であるImageViewのセンター座標を更新する。

3.移動量をリセットする

移動の処理が異なるだけで、ローテーションやピンチとやってることはあまり変わらないので、特に悩むことは無いはずだ。

さあ、実行してみよう。
移動することが出来た!

スワイプ
次はスワイプを実装する。
パンとの違いだが、スワイプは指を軽く弾くようにするジェスチャーだ。
ここも基本的な手順はローテーション等と変わらない。
実装はデバッグ出力を表示するようにしよう。

さあ、実行してみよう。
デバッグ出力が表示されずに、パンの処理が行われたはずだ。
これは、パンとイベントが被っているためだ。

そこで、イベントが被らないようにイベントの発生条件を変更する。
具体的にはこうだ。
  • パンは1本指で行う
  • スワイプは2本指で行う
まず、PanGestureRecognizerのAttributes InspectorでTouchesのMaximumを1に設定する。
ios_gesture_ss9
次にSwipeGestureRecognizerのAttributes InspectorでTouchesを2に設定する。
ios_gesture_ss10
これで準備完了だ。
実行してみよう。
イベントがかち合わずに、スワイプのデバッグ出力が表示された!

ちなみに、スワイプは一つのSwipeGestureRecgnizerで一つの方向しか設定できない。
(デフォルトでは右側)
なので、必要に応じて追加しよう。
ios_gesture_ss11

長押し
最後は長押しを実装する。
とは言っても、手順や実装はタップとほとんど同じだ。

これで実行してみよう。
長押しのデバッグ出力が表示されたはずだ。
しかし、指を話した時にもデバッグ出力が表示されたことに気付くだろう。
これは、イベントには様々な状態があるためだ。
次のセクションでこれについて説明する。

イベントの状態
イベントには様々な状態がある。
イベントが開始した、イベントが継続して起こった、イベントが終了した等だ。
詳細は公式のリファレンスを見てほしい。
UIGestureRecognizer Class Reference

ここでは例として先ほどの長押しを状態毎に処理を分けてみよう。

これで実行してみよう。
各状態毎のデバッグ出力が表示された!

参考文献
UIGestureRecognizer Tutorial in iOS 5: Pinches, Pans, and More! | Ray Wenderlich