MILLEN BOX

音楽好きの組み込みソフトエンジニアによるプログラミング(主にiOSアプリ開発)の勉強の記録

連打アプリをコスリ対応するには? [swift1.2] [GestureRecognizer]

連打アプリを作成中です。
連打といえばシュウォッチを思い出す方も多いのではないでしょうか。
そしてシュウォッチといえば、コスリを使った連打ですよね。
本日はコスリ機能への対応はどのように行えばいいのかということについて書いていきたいと思います。

本日のGithubは以下を参照下さい。

GitHub - anthrgrnwrld/kosuri

自分ポイント1

コスリ機能対応のためにはどのようにすればよいか?
自分で考えて途方にくれていたところ、 UIPanGestureRecognizerを使ったらいいですよ とのアドバイス頂きました。
(@akio0911 さんありがとうございます!)
で、UIPanGestureRecognizerって何?どうやって使うの?というところ。 アドバイスを頂いた時にサンプルコードを頂いていたのですが、
その時の私ではうまく動かすことが出来ませんでした。
もうちょっと勉強しないと実装できそうにないと感じ、以下のページで勉強をしました。

040 GestureRecognizerのイベント取得 - Swift Docs

わかったこと

  • GestureRecognizerという様々なタップ関連動作からイベントを取得するクラスがある(と理解しました。)
  • GestureRecognizerの中でUIPanGestureRecognizerはPan動作(コスリ動作)をした時にイベントを発生させる(と理解しました。)
  • GestureRecognizerの使用方法1 → viewDidLoad 内でGestureRecognizer関連クラスをインスタンス化し、その際にイベント発生時に実行する動作を指定する。
  • GestureRecognizerの使用方法2 → ターゲットとなるviewに対しaddGestureRecognizerをする。

コードで書くとこんな感じになります。ボタンに対しコスリ動作をしたらログを吐くようにしていますので、どのような動作をすればイベントが発生するかわかると思います。

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    @IBOutlet weak var label: UILabel!

    var count = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.label.text = "\(count)"
        let myTap = UIPanGestureRecognizer(target: self, action: "didPan:")
        self.button.addGestureRecognizer(myTap)
    }
    
    @IBAction func pressButton(sender: AnyObject) {
        count++
        self.label.text = "\(count)"
    }
    
    func didPan(sender: AnyObject) {

        println("\(__FUNCTION__) is called!")

        //コスられた時に行う動作をここに書きます。
    }

}

自分ポイント2

ここまでくれば出来たも当然!!func didPanの中にカウントアップ処理書けばいいんでしょ?なんて思っているとえらいことになります。
どれだけの移動量でPanイベントを発生させるかはiOS次第なので、本来行いたいイベントの発生(コスリの最中、ボタンの範囲からのイン/アウトでカウントアップ)とはならない訳です。
この要件を満たすためのコードは以下になります。
ボタンの範囲からのイン/アウトをフラグで管理する訳です。(@akio0911 さんのサンプルからアイデア拝借いたしました。本当にありがとうございます。)

class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    @IBOutlet weak var label: UILabel!
    
    var inButton = false
    var count = 0
    
    ...
    
    func didPan(sender: AnyObject) {
        println("\(__FUNCTION__) is called!")

        if let pan = sender as? UIPanGestureRecognizer {

            let p = pan.locationInView(self.view)
            if !inButton &&  self.button.frame.contains(p)
            {
                count++
                inButton = !inButton
                self.label.text = "\(count)"
            }else if inButton && !self.button.frame.contains(p) {
                inButton = !inButton
            }
        }
    }

}

gifアニメをのせときます。
f:id:anthrgrnwrld:20150904203102g:plain

この実装を基に連打アプリのアップデートを行い、想定通りのコスリ機能を実装することができました。 大変満足しております。