swiftxcodeuigesturerecognizeruipangesturerecognizer

How do I move other objects when I use GestureRecognizer?


I created a view with buttons and added the ability to move them using UIGestureRecognizer. I would like that when I start moving some buttons, the other buttons start moving as well, just like when I move apps on my iPhone. How do I get this to work?

Here is my code:

import UIKit

class ViewController: UIViewController, UIGestureRecognizerDelegate {
    
    var source = [String]()
    var buttonView = UIView()
    var dragg = UIPanGestureRecognizer()
    private var initialCenter: CGPoint = .zero

    override func viewDidLoad() {
        super.viewDidLoad()
        
        for _ in 0..<30 {
            let rs = String.random()
            source.append(rs)
        }
        
        dragg.delegate = self
     
        buttonView.frame = CGRect.init(x: 0, y: 50, width: self.view.frame.size.width, height: self.view.frame.size.height)
        self.view.addSubview(buttonView)
        
        buttons()
    }

    
    func buttons() {
        
            buttonView.subviews.forEach({ $0.removeFromSuperview() })

            let offset = 10 // set offset on X & Y axes
            let btnsOnX = 5 // how many buttons in row
        
            let btnSize = ((Int(UIScreen.main.bounds.width)) - (offset * (btnsOnX + 1))) / btnsOnX
            var xRow = 0
            var xPosMultiplier = 0
            
            for (i,element) in source.enumerated(){

                xPosMultiplier += 1
                
                if (i % btnsOnX == 0) { // change row
                    xRow += 1
                    xPosMultiplier = 0
                   
                }
               
                let xPos = offset + (xPosMultiplier * offset) + (xPosMultiplier * btnSize)
                let yPos = (offset + (xRow * offset) + (xRow * btnSize)) - (btnSize + offset)
                
                
                let btn = UIButton()
                btn.frame = CGRect(x: CGFloat(xPos), y: CGFloat(yPos + 0), width: CGFloat(btnSize), height: CGFloat(btnSize))
                btn.tag = i
                btn.layer.borderWidth = 0.5
                
                btn.layer.cornerRadius = 10
                btn.layer.borderColor = UIColor.lightGray.cgColor
                btn.setTitle("\(element)", for: UIControl.State())
                btn.titleEdgeInsets.left = 5
                btn.titleEdgeInsets.right = 5
                btn.backgroundColor = UIColor.white
                btn.setTitleColor(UIColor.systemBlue, for: UIControl.State())
                btn.titleLabel!.lineBreakMode = .byWordWrapping
                btn.titleLabel!.textAlignment = .center
                btn.titleLabel?.font = UIFont.systemFont(ofSize: CGFloat(10), weight: UIFont.Weight.bold)
               
                dragg = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
                btn.addGestureRecognizer(dragg)
                
                buttonView.addSubview(btn)
             
                if (i % btnsOnX  == 0) {
                    xPosMultiplier = 0 // reset with new row after x was set
                }
            }
        
    }
    

    
    @objc func handlePan(_ sender: UIPanGestureRecognizer) {
        if sender.state == .began || sender.state == .changed {

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

}

extension String {

    static func random(length: Int = 10) -> String {
           let base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
           var randomString: String = ""

           for _ in 0..<length {
               let randomValue = arc4random_uniform(UInt32(base.count))
               randomString += "\(base[base.index(base.startIndex, offsetBy: Int(randomValue))])"
           }
           return randomString
       }
    
   }


I would like to ask how to create some "map" of buttons, or is it all handled differently?

I couldn't find anything on Google, unfortunately.

Preview: enter image description here


Solution

  • Your best choice would be to implement this with a UICollectionView with a UICollectionViewDragDelegate and UICollectionViewDropDelegate. With a fairly simple implementation you will get what you want out of the box.

    There is a plenty of tutorials on the internet that explain how to do it, but here is the link to the official documentation: Supporting Drag and Drop in Collection Views.