【Swift】Long Press Gesture Recognizerの使い方。部品の長押しを検知する。(Swift 2.1、XCode 7.2)
Long Press Gesture Recognizerとは
本記事ではSwiftで使える部品のLong Press Gesture Recognizer(以下、ロングプレスリコグナイザー)の使い方について説明する。
ロングプレスリコグナイザーとは、長押しを検知する部品である。似ている部品のTap Gesture Recognizer(以下、タップリコグナイザー)は指が画面に触れただけで検知されるので誤タップが起きやすい。
一方、ロングプレスリコグナイザーは検知までに一定時間が必要なので誤タップが起きにくい。ゆえに、誤タップしそうな状況を回避するために利用させることが多い。
マップビューの記事で、地図を長押しした位置にピンを刺す動きをロングプレスリコグナイザーを用いて実装しているので、そちらも参照されたし。⇒「記事」
ロングプレスリコグナイザーを使ってみる
デバイス画面にラベルを配置する(下図赤矢印)。黄緑枠のアトリビュートインスペクタボタンを押して設定画面を表示し、Colorに白、Backgroundに青色、User Interaction Enabledにチェックを入れる。
紫枠のアシスタントエディタボタンを押してViewController.swfitを開く。Ctrlキーを押しながらドラッグ&ドロップでラベルをソースコードまで運んで吹き出しの設定画面を表示させる。
Connectionに「Outlet」、Nameに「testsLabel」を入力してConnectボタンを押す。これでソースコードでラベルを操作できるようになった。
ロングプレスリコグナイザーをラベルに配置する(下図赤矢印)。Ctrlキーを押しながら黄緑枠のロングプレスリコグナイザーをドラッグ&ドロップでソースコードまで運んで吹き出しの設定画面を表示させる。
Connectionに「Action」、Nameに「pressLabel」、Typeに「UILongPressGestureRecognizer」を入力してConnectボタンを押す。これで長押しのイベントをソースコードで受けれるようになった。
ViewController.swiftを以下のコードに変更する。
「長押し時の呼び出しメソッド」は長押し開始と終了の2回呼び出されるので、ステータスから開始と終了を判別し、ラベルに表示している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// // ViewController.swift // import UIKit class ViewController: UIViewController { @IBOutlet weak var testLabel: UILabel! //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() } //長押し時の呼び出しメソッド @IBAction func pressLabel(sender: UILongPressGestureRecognizer) { //呼び出されたタイミングを確認する。 if(sender.state == UIGestureRecognizerState.Began) { testLabel.text = "長押し開始" } else if (sender.state == UIGestureRecognizerState.Ended) { testLabel.text = "長押し終了" } } } |
以下は実際のプレイ動画
ロングプレスリコグナイザーの設定
ロングプレスリコグナイザーのアトリビュートインスペクタを確認する。
設定項目は以下の4項目で、すべての条件をクリアすると長押しと判定される。
設定名 | 説明 | |
---|---|---|
1 | Min Duration | 長押しと判定されるまでの時間の長さ。例えば「2.5」に設定すると、指が部品に触れてから2.5秒後に「長押し開始」が通知される。 |
2 | Taps | 長押し前のタップ数。例えば「3」に設定すると、部品を3タップしたあとの4タップ目を部品に触れたままにする。 |
3 | Touches | 長押し時の指の数。例えば「2」に設定すると、同時に2本の指で部品を触る。 |
4 | Tolerance | 指が画面に触れたあとの移動可能範囲をポイントで指定する。例えば「30」に設定すると、指が部品に触れてから半径約1cmまで指がズレても長押し判定に影響はない。 |
以下の動画はMin Durationを「2.5」、Tapsを「3」、Touchesを「2」、Toleranceを「200」に設定したときのプレイ動画
タップリコグナイザーと合わせた場合どうなるか
ロングプレスリコグナイザーと似ている部品といえばタップリコグナイザー。2つの部品の大きな違いは押している時間の長さである。この2つのリコグナイザーを1つの部品に配置した場合はどうなるかを確かめてみよう。
タップリコグナイザーをラベルに配置する(下図赤矢印)。水色枠のアシスタントエディタボタンを押してViewController.swiftを開く。Ctrlキーを押しながら紫枠のタップリコグナイザーをドラッグ&ドロップでソースコードまで運んで吹き出しの設定画面を表示させる。
Connectionに「Action」、Nameに「tapLabel」、Typeに「UITapGestureRecognizer」を入力してConnectボタンを押す。これでラベルをタップしたときのイベントをソースコードで受けれるようになった。
ViewController.swiftを以下のコードに変更する。「タップ時の呼び出しメソッド」でラベルの背景色をランダムな色に変更している。「長押し時の呼び出しメソッド」は変更なし。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
// // ViewController.swift // import UIKit class ViewController: UIViewController { @IBOutlet weak var testLabel: UILabel! //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() } //タップ時の呼び出しメソッド @IBAction func tapLabel(sender: UITapGestureRecognizer) { //ラベルの背景色をランダムな色に変更する。 testLabel.backgroundColor = UIColor(red: CGFloat(drand48()), green: CGFloat(drand48()), blue: CGFloat(drand48()), alpha: 1.0) } //長押し時の呼び出しメソッド @IBAction func pressLabel(sender: UILongPressGestureRecognizer) { //呼び出されたタイミングを確認する。 if(sender.state == UIGestureRecognizerState.Began) { testLabel.text = "長押し開始" } else if (sender.state == UIGestureRecognizerState.Ended) { testLabel.text = "長押し終了" } } } |
以下は実際のプレイ動画。「長押し時の呼び出しメソッド」が実行されたときは「タップ時の呼び出しメソッド」は実行されなかった。つまり、長押しにならなかった場合のみタップと判定されるということだ。
ちなみに、「長押し時の呼び出しメソッド」が呼ばれたときに「タップ時の呼び出しメソッド」も呼んでほしい場合の実装方法は以下になる。
Ctrlキーを押しながら下図赤枠のロングプレスリコグナイザーをドラッグ&ドロップでソースコードまで運んで吹き出しの設定画面を表示させる。Connectionに「Outlet」、Nameに「longPressRecognizer」を入力しConnectボタンを押す。
黄緑枠のタップリコグナイザーも同様にして吹き出しの設定画面を表示し、Connectionに「Outlet」、Nameに「tapRecognizer」を入力しConnectボタンを押す。これでロングプレスリコグナイザーとタップリコグナイザーをソースコードで操作できるようになった。
ViewController.swiftを以下のコードに変更する。デリゲートメソッドの「リコグナイザーの同時検知を許可するメソッド」を実装して、2つのリコグナイザーの検知が同時に行われるようにした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
// // ViewController.swift // import UIKit class ViewController: UIViewController, UIGestureRecognizerDelegate { @IBOutlet weak var testLabel: UILabel! @IBOutlet var longPressRecognizer: UILongPressGestureRecognizer! @IBOutlet var tapRecognizer: UITapGestureRecognizer! var aaa:Bool = false //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //デリゲート先を自分に設定する。 longPressRecognizer.delegate = self tapRecognizer.delegate = self } //タップ時の呼び出しメソッド @IBAction func tapLabel(sender: UITapGestureRecognizer) { print("タップ呼び出し") //ラベルの背景色をランダムで変更する。 testLabel.backgroundColor = UIColor(red: CGFloat(drand48()), green: CGFloat(drand48()), blue: CGFloat(drand48()), alpha: 1.0) } //長押し時の呼び出しメソッド @IBAction func pressLabel(sender: UILongPressGestureRecognizer) { print("長押し呼び出し") //呼び出されたタイミングを確認する。 if(sender.state == UIGestureRecognizerState.Began) { testLabel.text = "長押し開始" } else if (sender.state == UIGestureRecognizerState.Ended) { testLabel.text = "長押し終了" } } //リコグナイザーの同時検知を許可するメソッド func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true } } |
以下は実際のプレイ動画。長押しとタップの両方の処理が実行されるようになった。
ただし、部品を押している時間が長いとタップリコグナイザーがタイムアウトして実行されない。なので、時間の長さで実行処理を振り分けるならロングプレスリコグナイザーを複数登録する作りにしたほうが良さそうだ。