Skip to content

Instantly share code, notes, and snippets.

@Darmaal
Created September 5, 2016 16:02
Show Gist options
  • Save Darmaal/d374a3a685ee9a733b0f6670da905c45 to your computer and use it in GitHub Desktop.
Save Darmaal/d374a3a685ee9a733b0f6670da905c45 to your computer and use it in GitHub Desktop.
import UIKit
class ViewController: UIViewController, UICollisionBehaviorDelegate {
let data = ["Getting sstartw with Swift","SiriKit Basic","SprieKit for Apple Watch"]
var views = [UIView]()
var animator:UIDynamicAnimator!
var gravity:UIGravityBehavior!
var snap:UISnapBehavior!
var previousTouchPoint:CGPoint!
var viewDragging = false
var viewPinned = false
override func viewDidLoad() {
super.viewDidLoad()
animator = UIDynamicAnimator(referenceView: self.view)
gravity = UIGravityBehavior()
animator.addBehavior(gravity)
gravity.magnitude = 4
var offset:CGFloat = 250
for i in 0 ... data.count - 1 {
if let view = addViewController(atOffset: offset, dataForVC: data[i]){
views.append(view)
offset -= 50
}
}
}
//optional return
func addViewController (atOffset offset:CGFloat, dataForVC data:AnyObject?) -> UIView? {
let frameForView = self.view.bounds.offsetBy(dx: 0, dy: self.view.bounds.size.height - offset)
let sb = UIStoryboard(name: "Main", bundle: nil)
let stackElementVC = sb.instantiateViewControllerWithIdentifier("StackElement") as! SEVC
if let view = stackElementVC.view {
view.frame = frameForView
view.layer.cornerRadius = 5
view.layer.shadowOffset = CGSizeMake(2, 2)
view.layer.shadowColor = UIColor.blackColor().CGColor
view.layer.shadowRadius = 3
view.layer.shadowOpacity = 0.5
//adding some data to our controller
if let headerStr = data as? String {
stackElementVC.headerString = headerStr
}
self.addChildViewController(stackElementVC)
self.view.addSubview(view)
stackElementVC.didMoveToParentViewController(self)
//pan gesture recognizer
//let pGr = UIPanGestureRecognizer(target: self, action: #selector(ViewController.handle)
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(ViewController.handlePan(_:)))
view.addGestureRecognizer(panGestureRecognizer)
let collision = UICollisionBehavior(items: [view])
//the following line is used to create the snappy smooth animation effect
collision.collisionDelegate = self
animator.addBehavior(collision)
//defining a boundary
let boundary = view.frame.origin.y + view.frame.size.height
// lower boundary
var boundaryStart = CGPoint(x: 0, y: boundary)
var boundaryEnd = CGPoint(x: self.view.bounds.size.width, y: boundary)
collision.addBoundaryWithIdentifier(1, fromPoint: boundaryStart, toPoint: boundaryEnd)
// upper boundary
boundaryStart = CGPoint(x: 0, y: 0)
boundaryEnd = CGPoint(x: self.view.bounds.size.width, y: 0)
collision.addBoundaryWithIdentifier(2, fromPoint: boundaryStart, toPoint: boundaryEnd)
gravity.addItem(view)
let itemBehavior = UIDynamicItemBehavior(items: [view])
animator.addBehavior(itemBehavior)
return view
}
return nil
}
func handlePan (gestureRecognizer:UIPanGestureRecognizer){
//getting the toucpoint -> where did our user click in hte screen
// let touchPoint = gestureRecognizer.locationOfTouch(in:, inView: self.view)
//let draggedView = gestureRecognizer.view!
let touchPoint = gestureRecognizer.locationInView(self.view)
let draggedView = gestureRecognizer.view!
if gestureRecognizer.state == .Began {
let dragStartPoint = gestureRecognizer.locationInView(draggedView)
// the y value here is fully depended on your scaling, meaning you can readjust this to your desire
if dragStartPoint.y < 200 {
viewDragging = true
previousTouchPoint = touchPoint
}
} else if gestureRecognizer.state == .Changed && viewDragging {
let yOffset = previousTouchPoint.y - touchPoint.y
draggedView.center = CGPoint(x: draggedView.center.x, y:draggedView.center.y - yOffset)
previousTouchPoint = touchPoint
} else if gestureRecognizer.state == .Ended && viewDragging {
pin(draggedView)
addVelocity(toView: draggedView, fromGestureRecgonizer: gestureRecognizer)
animator.updateItemUsingCurrentState(draggedView)
viewDragging = false
}
}
//determinor
func pin (view:UIView){
let viewHasReachedPinLocation = view.frame.origin.y < 100
if viewHasReachedPinLocation {
if !viewPinned {
//creating the snappy behavior
var snapPosition = self.view.center
snapPosition.y += 30
snap = UISnapBehavior(item: view, snapToPoint: snapPosition)
animator.addBehavior(snap)
setVisibility(view, alpha: 0)
viewPinned = true
}
} else {
if viewPinned {
animator.removeBehavior(snap)
setVisibility(view, alpha: 1)
viewPinned = false
}
}
}
func setVisibility(view:UIView, alpha:CGFloat){
for aView in views {
if aView != view {
aView.alpha = alpha
}
}
}
//detects if one of the items is thrown, and attempt to apply semi-realistic physics to it
func addVelocity(toView view:UIView, fromGestureRecgonizer panGesture:UIPanGestureRecognizer){
var velocity = panGesture.velocityInView(self.view)
velocity.x = 0
if let behavior = itemBehavior(forview: view){
behavior.addLinearVelocity(velocity, forItem: view)
}
}
// this function will iterate until it finds the perfect UIDYNBHV, then apply the linaer velocity
func itemBehavior (forview view:UIView) ->UIDynamicItemBehavior? {
for behavoir in animator.behaviors {
if let itemBehavior = behavoir as? UIDynamicItemBehavior {
if let possibleView = itemBehavior.items.first as? UIView where possibleView == view {
return itemBehavior
}
}
}
return nil
}
//
// func collisionBehavior(UICollisionBehavior, beganContactForItem: UIDynamicItem, withBoundaryIdentifier: NSCopying?, atPoint: CGPoint){
//
// if NSNumber(IntegerLiteralType: 2).isEqual(identifer){
//
// }
//
// }
func collisionBehavior(behavior: UICollisionBehavior, beganContactForItem item: UIDynamicItem, withBoundaryIdentifier identifier: NSCopying?, atPoint p: CGPoint) {
if NSNumber(integerLiteral: 2).isEqual(identifier){
let view = item as! UIView
pin(view)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment