UIViewのドラッグ (生)


タップ検知方法は、
生のタップ情報から任意イベントを検知をする自由度が高い方法と、
UIGestureRecognizerが用意した基本タップイベントのテンプレートを使う方法
の主に二つがあるが、
前者の生でもドラッグ検知だけなら簡単ということがわかったので、試してみた。

実装

DraggableView.swift
import UIKit

// ドラッグだけ実装したヴュー
class DraggableView: UIView {
    // ドラッグ検知メソッド
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {// このビューへのタップ取得。ちなみにデフォルトではマルチタップのプロパティはfalseになってるので、ここではfirstのみ考えればおk。
            assert(false)
        }
        let loc = touch.location(in: self.superview)
        let oldLoc = touch.previousLocation(in: self.superview)// 動かす前の座標
        // 前の位置と差分をとって、その分ヴューを動かす。
        let diffX = loc.x - oldLoc.x
        let diffY = loc.y - oldLoc.y

        var center = self.center
        center.x += diffX
        center.y += diffY

        self.center = center
    }
}

動作

Videotogif.gif

原理

ざっくりいうと、
・デバイスで検知したタップイベント情報(座標、タップ状態(開始、ステイ、ドラッグ中、終了)、等)をアプリケーションが受け取って、
・アプリケーションはそれをタップ対象のviewに渡して(厳密にはUIViewが継承してるUIResponderに渡して)、
・view側ではタップ状態に対応した(UIResponderの)メソッドが呼ばれるようになっている(今回で言うとドラッグ中→touchesMoved())

ということみたい。

拡大など複数の指による操作も、touchesMoved()以外のタップ状態に対応したメソッドも駆使すればできる模様
ただ、このように生のタップイベント情報を使って実装するとコードが複雑化していくので、ドラッグなどの単純なタップイベント検知はUIGestureRecognizerにテンプレートが用意されているので、UIGestureRecognizerの方を使った方がいいとのこと。

UIGestureRecognizerでのドラッグも試した:

参考文献