2019年2月14日木曜日

縦横それぞれで拡大縮小できるUIPinchGestureRecognizer

はじめに

標準のUIPinchGestureRecognizerだと得られるScaleはタッチした2点の距離をベースに計算されます。そのため、縦に伸ばしたか横に伸ばしたかは結果に反映されません。
縦横それぞれでScaleが欲しかったため、UIPinchGestureRecognizerを拡張してTwoDimentionsPinchGestureRecognizerというクラスを作成しました。

実装と解説

実際のコード

class TwoDimentionsPinchGestureRecognizer : UIPinchGestureRecognizer {
    private var initPinchWidth : Float = 0
    private var initPinchHeight : Float = 0
    private var _scaleX : Float = 0
    private var _scaleY : Float = 0
    
    var scaleX : Float {
        get { return _scaleX }
    }
    var scaleY : Float {
        get { return _scaleY }
    }
    
    override func touchesBegan(_ touches: Set, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
        
        guard touches.count == 2 else { return }
        
        let locations = touches.compactMap { touch in
            return touch.location(in: self.view)
        }
        
        initPinchWidth = Float(abs(locations[0].x - locations[1].x))
        initPinchHeight = Float(abs(locations[0].y - locations[1].y))
    }
    
    override func touchesMoved(_ touches: Set, with event: UIEvent) {
        super.touchesMoved(touches, with: event)
        
        guard touches.count == 2 else { return }
        
        let locations = touches.compactMap { touch in
            return touch.location(in: self.view)
        }

        let newPinchWidth = Float(abs(locations[0].x - locations[1].x))
        let newPinchHeight = Float(abs(locations[0].y - locations[1].y))
        
        _scaleX = newPinchWidth / initPinchWidth
        _scaleY = newPinchHeight / initPinchHeight
    }
}

解説

まず、touchesBeganで初回のタッチした2点間の縦横それぞれの距離を計算します。そして、touchesMovedで初回の縦横の距離からどれだけ変わったかの比率を計算して、それぞれscaleXとscaleYとして値を呼び出し元に渡します。
尚、touchesBeganとtouchesMovedで取得されるtouchesはSetのため順番が保証されていません。より完成度を求めるならばcompactMapで得られた結果をソートする必要があります。


TwoDimentionsPinchGestureRecognizerのデモ


0 件のコメント:

コメントを投稿