MILLEN BOX

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

OekakiGestureRecognizer (touchDownを認識するGestureRecognizer) [UIGestureRecognizer]

現在簡単なお絵描き機能を持ったアプリを作成中ですが、その実現方法として当初UIPanGestureRecognizerを使用してタップ・タッチを検出していました。
しかしUIPanGestureRecognizerでお絵描き機能を実現した場合、画面に指を引っ付けて指を動かしたり離したりした時にタップが検出されます。
画面にタップした瞬間は検出されません。よって画面をタップして指を動かさない場合には、お絵描きの実行はされないのです。

しかし現実世界では紙に筆を落とした瞬間に墨の色が付くわけで。
今回はその実現のため、 UIGestureRecognizer を拡張した OekakiGestureRecognizer を作ってみましたのでメモしておきます。

Githubは以下です。

github.com

OekakiGestureRecognizer

import UIKit
import UIKit.UIGestureRecognizerSubclass

class OekakiGestureRecognizer: UIGestureRecognizer
{
    
    var touchPoint: CGPoint?                                //タッチ座標を格納
    
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent)
    {
        
        let numberOfTouches = event.allTouches()!.count     //タッチした指の本数を取得
        
        if numberOfTouches != 1 {
            self.state = .Cancelled                         //タッチ本数が1本以外の場合はstateをCancelに
        }
        
        if self.state == .Possible {
            let touch = touches.first! as UITouch
            touchPoint = touch.locationInView(self.view)    //タッチ座標を取得・格納
            self.state = .Began                             //stateをBeganに
        }
    }
    
    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent) {
        let touch = touches.first! as UITouch
        touchPoint = touch.locationInView(self.view)        //タッチ座標を取得・格納
        self.state = .Changed                               //stateをChangedに
    }
    
    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent) {
        let touch = touches.first! as UITouch
        touchPoint = touch.locationInView(self.view)        //タッチ座標を取得・格納
        self.state = .Ended                                 //stateをEndedに
    }
    
    override func touchesCancelled(touches: Set<UITouch>, withEvent event: UIEvent) {
        let touch = touches.first! as UITouch
        touchPoint = touch.locationInView(self.view)        //タッチ座標を取得・格納
        self.state  = .Cancelled                            //stateをCancelledに
    }
    
    override func locationInView(view: UIView?) -> CGPoint {

        guard var tchpnt = touchPoint else {
            fatalError("Can't get touchPoint")
        }
        
        //parameterのviewがUIScrollViewか否かで処理を分岐(拡大時対応の為)
        if let parameterView = self.view! as? UIScrollView {
            
            let contentSize = parameterView.contentSize
            let rate = self.view!.bounds.width / contentSize.width
            
            tchpnt.x = tchpnt.x * rate
            tchpnt.y = tchpnt.y * rate
            
            return tchpnt                                   //parameterのviewがUIScrollViewだった時

        } else {
            return tchpnt                                       //parameterのviewがUIScrollView以外だった時
        }


    }

    
}

正直検証しきれてないので想定していない動作で何が起こるか分かってませんが、
恐らく想定していない動作については「何も起こらない」ようになっている為、大きな問題にはならないんじゃないかと楽観的に考えています。