Search code examples
arraysswiftlinked-listuipangesturerecognizerinfinite

Place infinite array of uiview objects on view controller


My goal of the swift code below is when pressBtn func is called a single black view is added to the center of the screen. The uiview in this code is called box. Each time box is added to the center of the screen it should be connected to a uipangesture which lets it move around you can see what I am looking for in the gif below. The black box is replaced with x for the gif.

enter image description here


Solution

  • You can create each view using a function:

    private func getBlackView() -> UIView {
        let view = UIView()
        view.backgroundColor = .black
        let sideLength: CGFloat = 100
        view.frame = .init(x: self.view.bounds.midX - sideLength / 2,
                           y: self.view.bounds.midY - sideLength / 2,
                           width: sideLength,
                           height: sideLength)
        let recognizer = UIPanGestureRecognizer(target: self,
                                                action: #selector(moveView(_:)))
        view.addGestureRecognizer(recognizer)
        return view
    }
    

    Then, in this function create UIPanGestureRecognizer and add it to each newly created view. The #selector of this recognizer should be:

    @objc
    private func moveView(_ recognizer: UIPanGestureRecognizer) {
        switch recognizer.state {
        case .began:
            print("gesture began")
        case .changed:
            let translation = recognizer.translation(in: self.view)
    
            recognizer.view!.center = .init(x: recognizer.view!.center.x + translation.x,
                                            y: recognizer.view!.center.y + translation.y)
            recognizer.setTranslation(.zero, in: self.view)
        default:
            break
        }
    }
    

    Here each time you get a gecture recognized and state is .changed, you should move your view by current translation and reset it.


    Example:

    public class MyViewController : UIViewController {
        public override func viewDidLoad() {
            super.viewDidLoad()
            button.frame = .init(x: self.view.bounds.midX,
                                 y: 0,
                                 width: 100,
                                 height: 100)
            self.view.addSubview(button)
        }
        
        private lazy var button: UIButton = {
            let button = UIButton()
            button.backgroundColor = .blue
            button.setTitleColor(.white, for: .normal)
            button.setTitle("add", for: .normal)
            button.addTarget(self,
                             action: #selector(addBlackView),
                             for: .touchUpInside)
            return button
        }()
        
        private func getBlackView() -> UIView {
            let view = UIView()
            view.backgroundColor = .black
            let sideLength: CGFloat = 100
            view.frame = .init(x: self.view.bounds.midX - sideLength / 2,
                               y: self.view.bounds.midY - sideLength / 2,
                               width: sideLength,
                               height: sideLength)
            let recognizer = UIPanGestureRecognizer(target: self,
                                                    action: #selector(moveView(_:)))
            view.addGestureRecognizer(recognizer)
            return view
        }
        
        @objc 
        private func addBlackView() {
            let view = getBlackView()
            self.view.addSubview(view)
        }
        
        @objc
        private func moveView(_ recognizer: UIPanGestureRecognizer) {
            switch recognizer.state {
            case .began:
                print("gesture began")
            case .changed:
                let translation = recognizer.translation(in: self.view)
    
                recognizer.view!.center = .init(x: recognizer.view!.center.x + translation.x,
                                                y: recognizer.view!.center.y + translation.y)
                recognizer.setTranslation(.zero, in: self.view)
            default:
                break
            }
        }
    }