UILongTapGuestureRecognizerで対処から位置がズレたらキャンセルする

UIButtonのような挙動をViewで作りたい時にはUILongTapGuestureRecognizerを使うことで実現できます。

ちなみにUITapGuestureRecognizerではボタンのような動きを再現することができません。それについては以前にk時にしたのでそちらを参照してみてくださいUITapGuestureRecognizerではbigin,cancellは取れない

コード

class ViewController: UIViewController {

    @IBOutlet weak var myView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let longTapGuesture: UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(thumbnailTap(_:)))
        longTapGuesture.minimumPressDuration = 0.0
        myView.addGestureRecognizer(longTapGuesture)
    }
    
    @objc private func thumbnailTap(_ sender: UILongPressGestureRecognizer) {
        let touchPos = sender.location(in: sender.view)
        switch sender.state {
        case .began:
            myView.backgroundColor = .systemGreen

        case .ended:
            myView.backgroundColor = .systemPink
            
        case .changed:
            let myViewPos = myView.frame.origin
            let normalizePos = CGPoint(x:  myViewPos.x + touchPos.x, y: myViewPos.y + touchPos.y)
            if !myView.frame.contains(normalizePos) {
                myView.backgroundColor = .systemPink
            }
        default: //キャンセルの処理
            myView.backgroundColor = .systemGreen

        }
    }

}

CGPointがViewの中に含まれるかの判定

UIViewのframeにはcontainsというメソッドが用意されているのでCGPointを渡すことで判定できます。

CGRectのSwiftっぽい扱い方

座標の正規化について

UILongPressGestureRecognizerをViewに対して付与するのでtapした座標はviewの左上を原点とした座標が帰ってきます。

そのためVC上の原点とViewの原点を合わせてあげないと、tapしている位置がviewの上なのかどうかを判定することができません。

let normalizePos = CGPoint(x:  myViewPos.x + touchPos.x, y: myViewPos.y + touchPos.y)