のーとぶっく

学んだことをまとめておく学習帳および備忘録

【Swift/UIKit】ドラッグで UIView を動かす

スーッと指で UIView を動かす処理を書き置き。
ドラッグ中に細かく何度も呼び出されるメソッド touchesMoved(_:with:) を使用する。

f:id:hirakana:20200221224443p:plain

イメージ

メソッドで行う処理のイメージはこんな感じ

  1. 指でドラッグを開始した位置(座標)と終了した(動かしてる途中でも一区切りの中で)位置を取得
  2. 開始位置と終了位置から移動距離を出す
  3. 移動した分を UIView の元の位置に足して反映

指を動かしている間、メソッドが呼ばれるたびにこの流れを繰り返す

コード

UIView を用意。ここではラベルを。

var sampleLabel: UILabel!

isUserInteractionEnabled を忘れずに。これでタッチを感知することを許可する。

sampleLabel = UILabel()
sampleLabel.frame = CGRect(x: 0, y: 0, width: 100, height: 50)
sampleLabel.center = self.view.center
sampleLabel.textAlignment = .center
sampleLabel.backgroundColor = .black
sampleLabel.textColor = .white
sampleLabel.text = "Move me!"

//タッチを受け付ける(デフォルトは false)
sampleLabel.isUserInteractionEnabled = true

self.view.addSubview(sampleLabel)

何度も呼ばれるメソッド内の処理。動かしたいものに触れた時だけ実行したいので、タッチイベントの情報を使って条件分岐。

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    
    //タッチイベント
    let aTouch = touches.first!
    
    //タッチされたものがラベルの場合
    if aTouch.view == sampleLabel {
        
        //指の移動先の座標
        let destLocation = aTouch.location(in: self.view)

        //指の移動前の座標
        let prevLocation = aTouch.previousLocation(in: self.view)

        //取得した座標を格納する変数
        var myFrame = sampleLabel.frame

        //X,Yの移動距離
        let deltaX = destLocation.x - prevLocation.x
        let deltaY = destLocation.y - prevLocation.y

        //移動距離分を足す
        myFrame.origin.x += deltaX
        myFrame.origin.y += deltaY

        //反映
        sampleLabel.frame = myFrame
        
    }
    
}

好みでタッチ開始、終了時にアニメーション

//タッチを感知した時に呼ばれるメソッド
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    
    if touches.first?.view == sampleLabel {
        
        UIView.animate(withDuration: 0.06, animations: {
            
            self.sampleLabel.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
            
        }) { (Bool) in
            
        }
        
    }
    
}
//指を離した時に呼ばれるメソッド
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    
    if touches.first?.view == sampleLabel {
        
        UIView.animate(withDuration: 0.1, animations: {
        
            self.sampleLabel.transform = CGAffineTransform(scaleX: 0.4, y: 0.4)
            self.sampleLabel.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
            
        }) { (Bool) in
            
        }
        
    }
    
}