(Swift) UIDynamic 예제

이전에 작성했던 UIDynamics 데모를 재작성했다.

  • swift3 문법을 적용했고,
  • 별도의 Xcode 프로젝트가 아니라 Playground 용으로 만들어서 바로 확인할 수 있게 했다.




class PlayViewController: UIViewController {
    // 손을 끌고 다닐 뷰
    lazy var draggableView: UIView = {
        let v = UIView(frame: CGRect(x:40, y:40, width:50, height: 50))
        v.backgroundColor = UIColor.blue()
        return v
    }()

    // 이동가능한 뷰를 위한 제스쳐 인식
    lazy var pan: UIPanGestureRecognizer = { [unowned self] in 
        let _pan = UIPanGestureRecognizer(target: self, 
                                          action: #selector(self.panned(_:)))
        return _pan
    }()

    let animator: UIDynamicAnimator



    override func viewDidLoad() {
        // 애니메이터 초기화 
        animator = UIDynamicAnimator(referencingView: self.view)
        super.viewDidLoad()

        view.addSubview(draggableView)
        draggableView.addGestureRecognizer(pan)

        // 중력, 충돌 behavior 생성
        let gravity: UIGravityBehavior = { 
            let g = UIGravityBehavior(items: [draggableView])
            return g
        }()

        let collision: UICollisionBehavior = { 
            let c = UICollisionBehavior(items: [draggableView])
            c.translatesReferenceBoundsIntoBoundary = true
            c.collisionMode = .boundaries
            // 화면 바닥면에 
            let bottomCoord = view.bounds.size.height
            c.addBoundary(withIdentifier:"block", 
                          from: CGPoint(x:0, y:bottomCoord) 
                          to: CGPoint(x:view.bounds.size.width, y:bottomCoord))
            return c
        }()

        animator.addBehavior(gravity)
        animator.addBehavior(collision)
    }

    /// 패닝이 일어날 때마다 호출되는 핸들러 
    func panned(_ sender: UIPanGestureRecognizer) {
        // 터치가 끝날 때 애니메이터가 draggableView를 재계산에 포함하도록 한다.
        if (sender.state == .ended) {
            animator.updateItem(usingCurrentState: draggableView)
        }
        // 매 이동 순간의 offset을 계산하여 뷰의 위치를 바꾼다.
        let translation = sender.translation(in:view)
        if let sview = sender.view {
            sview.center = CGPoint(x: sview.center.x + translation.x,
                                   y: sview.center.y + translation.y)
            sender.setTranslation(CGPoint.zero)
        }
    }
}

let vc = PlayViewController()
PlaygroundPage.current.liveView = vc.view
PlaygroundPage.current.needsIndefiniteExecution = true