見出し画像

【徒然iOS】気ままにUIKit68〜Pan Gesture Recognizerの使い方 ドラッグ&ドロップを検知〜

概要

このマガジンは四十を過ぎたおっさんが、

を参考にStoryboardでiOSアプリを完全に趣味で楽しんでいるだけな記事を気ままに上げてます。

今回

をハイ、レッツゴ🕺

前準備

念の為、

  1. バックアップ

  2. 新しいクラス

  3. ビューコントローラの追加

  4. イニシャルビューの変更

をいつも通りやってから本題へ💃

こんな感じで!!!!

本題

パンリコグナイザーとは、

ドラッグ&ドロップを検知する部品

スワイプリコグナイザー:素早く指を動かさなければ検知されない。
パンリコグナイザー:ゆっくり指を動かしても検知され、元の位置からの移動量を正確に把握できる。

⒈ラベルを配置し、設定を変更して、アウトレット接続

適当に見やすくなるようにして〜〜〜
前回までと同じくアウトレット接続〜〜〜

⒉パンリコグナイザーをラベルに配置して、アクション接続

選んで〜〜〜
アクション接続〜〜〜
接続できた💃

⒊コードを組み込み

//
//  ViewController.swift
//
import UIKit
class ViewController: UIViewController {
    @IBOutlet weak var testLabel: UILabel!
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    //ドラッグ時の呼び出しメソッド
    @IBAction func panLabel(sender: UIPanGestureRecognizer) {
        //移動量を取得する。
        let move:CGPoint = sender.translationInView(view)
        //ドラッグした部品の座標に移動量を加算する。
        sender.view!.center.x += move.x
        sender.view!.center.y += move.y
        //ラベルに現在座標を表示する。
        //testLabel.text = "\(sender.view!.frame.origin.x), \(sender.view!.frame.origin.y)"
        //移動量を0にする。
        sender.setTranslation(CGPointZero, inView:view)
    }
}

「ドラッグ時の呼び出しメソッド」が指を移動するたびに呼び出されるので、引数から移動量を取得してラベルの座標に加算している。
👉移動量は蓄積する値なので0にしてからメソッドを抜けることで次の呼び出しに備えている。

てことらしい👀

今回のコード(シンプルパン)

class PanGestureViewController: UIViewController {
    
    @IBOutlet weak var myLabel: UILabel!
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    //ドラッグ時の呼び出しメソッド
    @IBAction func myPan(_ sender: UIPanGestureRecognizer) {
        //移動量を取得する。
        let move:CGPoint = sender.translation(in: view)
        //ドラッグした部品の座標に移動量を加算する。
        sender.view!.center.x += move.x
        sender.view!.center.y += move.y
        //ラベルに現在座標を表示する。
        //myLabel.text = "\(sender.view!.frame.origin.x), \(sender.view!.frame.origin.y)"
        //移動量を0にする。
        sender.setTranslation(CGPointZero, in:view)
    }
}

⒋シミュレータで実行

起動直後
適当にドラッグ後👀
動いたね🕺

⒌コメントアウトされてた座標軸をラベル表示のコードをコメント外して〜〜〜

今回のコード(シンプルパンラベル見出し)

class PanGestureViewController: UIViewController {
    
    @IBOutlet weak var myLabel: UILabel!
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    //ドラッグ時の呼び出しメソッド
    @IBAction func myPan(_ sender: UIPanGestureRecognizer) {
        //移動量を取得する。
        let move:CGPoint = sender.translation(in: view)
        //ドラッグした部品の座標に移動量を加算する。
        sender.view!.center.x += move.x
        sender.view!.center.y += move.y
        //ラベルに現在座標を表示する。
        myLabel.text = "\(sender.view!.frame.origin.x), \(sender.view!.frame.origin.y)"
        //移動量を0にする。
        sender.setTranslation(CGPointZero, in:view)
    }
}
やってみた!
別に今の環境だと、ラベル更新しても元に戻らないね👀

なので、以降の設定は、あくまでも参考

⒈ラベルの幅と高さの制約を追加

追加〜〜〜

⒉ビュー全体からの位置制約を追加

追加〜〜〜

⒊制約をそれぞれアウトレット接続

追加後〜〜〜

⒋コードを組み込む

//
//  ViewController.swift
//
import UIKit
class ViewController: UIViewController {
    @IBOutlet weak var testLabel: UILabel!
    @IBOutlet weak var xConstraint: NSLayoutConstraint!
    @IBOutlet weak var yConstraint: NSLayoutConstraint!
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    //ドラッグ時の呼び出しメソッド
    @IBAction func panLabel(sender: UIPanGestureRecognizer) {
        //移動量を取得する。
        let move:CGPoint = sender.translationInView(view)
        //ラベルの位置の制約に移動量を加算する。
        xConstraint.constant += move.x
        yConstraint.constant += move.y
        //画面表示を更新する。
        view.layoutIfNeeded()
        //ラベルに現在座標を表示する。
        testLabel.text = "\(sender.view!.frame.origin.x), \(sender.view!.frame.origin.y)"
        //移動量を0にする。
        sender.setTranslation(CGPointZero, inView:view)
    }
}

を参考に。コード

class PanGestureViewController: UIViewController {
    
    @IBOutlet weak var myLabel: UILabel!
    @IBOutlet weak var xConstraint: NSLayoutConstraint!
    @IBOutlet weak var yConstraint: NSLayoutConstraint!
    
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    //ドラッグ時の呼び出しメソッド
    @IBAction func myPan(_ sender: UIPanGestureRecognizer) {
        //移動量を取得する。
        let move:CGPoint = sender.translation(in: view)
        //ラベルの位置の制約に移動量を加算する。
        xConstraint.constant += move.x
        yConstraint.constant += move.y
        //画面表示を更新する。
        view.layoutIfNeeded()
        //ラベルに現在座標を表示する。
        myLabel.text = "\(sender.view!.frame.origin.x), \(sender.view!.frame.origin.y)"
        //移動量を0にする。
        sender.setTranslation(CGPointZero, in:view)
    }
}

⒌シミュレータを実行

動きはするけど、かなりおかしな動きになってるね👀

PINの順番をサイト記事と変えたことが原因かもしれないので〜〜〜
一度、制約を解除して、
サイト記事の手順どおりにやると〜〜〜

動きが普通になった🕺
けど、やっぱり2個目と動きに変化なし👀

今回のポイント

手順がひとつ違うだけで、優先される制約などから、期待どおりの動きができないこともあるので、手順はしっかり意識🕺
まあ、おかしくなったら、

なんかを参考に、正常なところまで戻れればいいけど、
UIKitはSwiftUIと違って、XIBファイルとの連携なんかも絡むので、

元に戻すのも、かなり面倒だし、
戻らないことも多い

👉なので、手順をきちんと意識する🕺

ブラッシュアップ

今回もAutoLayoutだけ〜〜〜

てな感じでラベルに追加して〜〜〜
コンフリクトが消えたので〜〜〜
シミュレータで実行すると、、、👀
てな感じで、制約がうまい具合にラベルを見やすくしてくれた

👉いいね〜〜〜〜

💃ま、用途に応じて、3つを使い分けてね🕺

Apple公式

さて、次回は

をレッツゴする🕺

いいなと思ったら応援しよう!