Wireframe

(Swift) UIDynamic 예제

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

UIDynamics를 적용하는 방법은 UIDynamicAnimator 객체를 만들고 여기에 애니메이션에 고려될 물리학적 요소 (중력이나 마찰등)를 behaivor로 설정해주면 된다. 애니메이터는 기준이 되는 레퍼런싱 뷰를 참조하면서 생성되고, 이후 해당 뷰 내의 뷰 계층 구조에 대해서 동역학을 계산하게 된다.


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
    }()
    // UIDynamicAnimator는 느긋하게 초기화한다.
    lazy var animator: UIDynamicAnimator = { [unowned self] in
      let anim = UIDynamicAnimator(referencingView: self.view)
      return anim
    }()
    override func viewDidLoad() {
        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
Exit mobile version