Search code examples
swiftloopsforeachvaruipangesturerecognizer

create universal variable for imageview to add uipangesture


My swift code below declares 2 imageviews and 2 uipangesutres. This code just ouptus 2 imageviews that can move around. What I want to do is create 1 uipangesture and have it apply to all of the imageviews. I am think there is a more efficent way to do this. Instead of declaring a var for every thing that needs to be move around in the view controller.

    import UIKit

  class ViewController: UIViewController {


var image1 = UIImageView(); var image2 = UIImageView()
var image1Pan = UIPanGestureRecognizer()
var image2Pan = UIPanGestureRecognizer()

override func viewDidLoad() {
    super.viewDidLoad()

    image1Pan = UIPanGestureRecognizer(target: self, action: #selector(ViewController.moveMethod))
    image1.addGestureRecognizer(image1Pan)

    image2Pan = UIPanGestureRecognizer(target: self, action: #selector(ViewController.moveMethod))
    image2.addGestureRecognizer(image2Pan)








    [image1,image2].forEach{
        $0.isUserInteractionEnabled = true

        view.addSubview($0)
        $0.translatesAutoresizingMaskIntoConstraints = false
    }



    // Do any additional setup after loading the view.
    NSLayoutConstraint.activate ([




        image1.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant :0),
        image1.topAnchor.constraint(equalTo: view.topAnchor, constant : 50),

        image1.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.10, constant: 0),
        image1.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.40, constant: 0),
        image1.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),




        image2.topAnchor.constraint(equalTo: view.topAnchor, constant : 50),

        image2.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.10, constant: 0),
        image2.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.40, constant: 0),
        image2.leadingAnchor.constraint(equalTo: image1.trailingAnchor, constant : 0),





    ])

    image1.backgroundColor = .blue
        image2.backgroundColor = .brown


}

@objc func moveMethod(_ sender: UIPanGestureRecognizer){



    let tranistioon = sender.translation(in: self.view)
    sender.view!.center = CGPoint(x: sender.view!.center.x + tranistioon.x, y: sender.view!.center.y + tranistioon.y)
    sender.setTranslation(CGPoint.zero,in: self.view)    }}

Solution

  • A Gesture Recognizer (such as `UIPanGestureRecognizer) is an object, not a property.

    It probably seems obvious that this code:

        // create a NEW instance of UIImageView each time throught the loop
        let imgView = UIImageView()
    
        var x: CGFloat = 50
        [UIColor.red, UIColor.green, UIColor.blue].forEach {
    
            // add imgView to self.view
            view.addSubview(imgView)
    
            // set imgView's properties
            imgView.backgroundColor = $0
            imgView.frame = CGRect(x: x, y: 100, width: 50, height: 50)
            x += 100
        }
    

    Will not result in 3 image views. It will give you one image view with a blue background with a frame of (250.0, 100.0, 50.0, 50.0). That's because you only created one image view, and you are only changing its properties each time through the loop.

    To get three image views (red, green and blue backgrounds) spaced 50-pts apart, you would need to do this:

        var x: CGFloat = 50
        [UIColor.red, UIColor.green, UIColor.blue].forEach {
    
            // create a NEW instance of UIImageView each time throught the loop
            let imgView = UIImageView()
    
            // add it to self.view
            view.addSubview(imgView)
    
            // set its properties
            imgView.backgroundColor = $0
            imgView.frame = CGRect(x: x, y: 100, width: 50, height: 50)
            x += 100
        }
    

    That's why you need to take the same approach with Gesture Recognizers. You need a new one for each object you wish to add it to.

    Depending on what all you will be doing, you can simplify things a bit:

        [image1, image2].forEach {
            $0.isUserInteractionEnabled = true
            view.addSubview($0)
            $0.translatesAutoresizingMaskIntoConstraints = false
    
            // create a NEW instance of UIPanGestureRecognizer
            let pg = UIPanGestureRecognizer(target: self, action: #selector(ViewController.moveMethod))
    
            // add it to $0 (an image view)
            $0.addGestureRecognizer(pg)
        }