I\'m trying to figure out implement UIKit Dynamics that are similar to those in Jelly\'s app (specifically swiping down to drag view off-screen).
See the animation:
SWIFT 3.0 :
import UIKit
class SwipeToDisMissView: UIView {
var animator : UIDynamicAnimator?
func initSwipeToDismissView(_ parentView:UIView) {
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(SwipeToDisMissView.panGesture))
self.addGestureRecognizer(panGesture)
animator = UIDynamicAnimator(referenceView: parentView)
}
func panGesture(_ gesture:UIPanGestureRecognizer) {
var attachment : UIAttachmentBehavior?
var lastTime = CFAbsoluteTime()
var lastAngle: CGFloat = 0.0
var angularVelocity: CGFloat = 0.0
if gesture.state == .began {
self.animator?.removeAllBehaviors()
if let gestureView = gesture.view {
let pointWithinAnimatedView = gesture.location(in: gestureView)
let offset = UIOffsetMake(pointWithinAnimatedView.x - gestureView.bounds.size.width / 2.0, pointWithinAnimatedView.y - gestureView.bounds.size.height / 2.0)
let anchor = gesture.location(in: gestureView.superview!)
// create attachment behavior
attachment = UIAttachmentBehavior(item: gestureView, offsetFromCenter: offset, attachedToAnchor: anchor)
// code to calculate angular velocity (seems curious that I have to calculate this myself, but I can if I have to)
lastTime = CFAbsoluteTimeGetCurrent()
lastAngle = self.angleOf(gestureView)
weak var weakSelf = self
attachment?.action = {() -> Void in
let time = CFAbsoluteTimeGetCurrent()
let angle: CGFloat = weakSelf!.angleOf(gestureView)
if time > lastTime {
angularVelocity = (angle - lastAngle) / CGFloat(time - lastTime)
lastTime = time
lastAngle = angle
}
}
self.animator?.addBehavior(attachment!)
}
}
else if gesture.state == .changed {
if let gestureView = gesture.view {
if let superView = gestureView.superview {
let anchor = gesture.location(in: superView)
if let attachment = attachment {
attachment.anchorPoint = anchor
}
}
}
}
else if gesture.state == .ended {
if let gestureView = gesture.view {
let anchor = gesture.location(in: gestureView.superview!)
attachment?.anchorPoint = anchor
self.animator?.removeAllBehaviors()
let velocity = gesture.velocity(in: gestureView.superview!)
let dynamic = UIDynamicItemBehavior(items: [gestureView])
dynamic.addLinearVelocity(velocity, for: gestureView)
dynamic.addAngularVelocity(angularVelocity, for: gestureView)
dynamic.angularResistance = 1.25
// when the view no longer intersects with its superview, go ahead and remove it
weak var weakSelf = self
dynamic.action = {() -> Void in
if !gestureView.superview!.bounds.intersects(gestureView.frame) {
weakSelf?.animator?.removeAllBehaviors()
gesture.view?.removeFromSuperview()
}
}
self.animator?.addBehavior(dynamic)
let gravity = UIGravityBehavior(items: [gestureView])
gravity.magnitude = 0.7
self.animator?.addBehavior(gravity)
}
}
}
func angleOf(_ view: UIView) -> CGFloat {
return atan2(view.transform.b, view.transform.a)
}
}